Le Menü encore

Im meinem ersten Beitrag zu einer mehr oder weniger radikalen Vereinfachung des Admin-Menüs in WordPress ging es um die Hintergründe der Idee an sich; hier folgt nun die Praxis.

Überblick

Screenshot: Admin-Menü vorher
Das hier (A) …
Screenshot: Admin-Menü nachher
… wird zu dem hier (B).

(Wer detailliertere Screenshots sehen möchte, findet sie im ersten Beitrag.)

Ziele

Mein Ziel war es, Cognitive Load zu reduzieren, indem ich das Admin-Menü ein Stück weit von der Last seiner eigenen Geschichte befreie, ohne jedoch seine Architektur als vertikale Liste zu verändern, oder seine Erweiterbarkeit durch Plugins grundsätzlich in Frage zu stellen.

Neben einer visuellen Stabilisierung des Menüs durch das Auslagern von Drittanbieter-Menüpunkten auf eine eigens dafür geschaffene Seite, ging es mir außerdem um die Reduzierung von Jargon.
Das Menü setzt, meiner Ansicht nach, in seiner Terminologie eine ganze Menge WordPress-Insiderwissen voraus; dem versuche ich mit einer groben Einteilung in vier Hauptbereiche – Dashboard, Content, Design, Setup – abzuhelfen, innerhalb derer ich dann die Menüpunkte neu ordne, oder einzelne einfach ganz weglasse.

Zum gegenwärtigen Zeitpunkt sind aus meinen angestrebten vier Hauptbereichen sechs geworden: zu den oben genannten gesellen sich noch Tools und Add-ons hinzu.

Für mich ist das keinesfalls der Weisheit letzter Schluss. Tools scheinen mir seit Site Health und DSGVO-Features als eigenständige Kategorie zwar tatsächlich sinnvoll, meine eigens hinzugefügte Seite Add-ons hingegen, von der aus alle Drittanbieter-Menüs erreichbar sind, könnte sicher auch unter Setup eingegliedert werden, denn da gehört sie, von der Idee her, eigentlich hin. Und der Seitentitel („Add-ons“) klingt zwar griffig, ist aber definitiv nicht das Nonplusultra.

Vorgehensweise

Es ist ein Plugin, klar. Und es ist erstmal ziemlich einfach gestrickt. Dies sind seine wesentlichen Schritte:

  1. Vorhandenes Admin-Menü innerhalb der Plugin-Klasse klonen.
  2. Den Klon nach meinen Vorstellungen umgestalten.
  3. Klon als Ganzes nach WordPress zurückspielen, so dass er das dort vorhandene Menü einfach komplett ersetzt.

Simpel. Der Teufel steckt, wie so oft, im Detail, aber dazu kommen wir gleich.

Screenshot: Action Hooks

Mein Plugin interagiert mit WordPress über vier verschiedene Hooks:

In diese hake ich insgesamt sieben Actions bzw. Filters ein (der Lesbarkeit halber hier ohne Namespace gelistet):

  1. store_menus() – holt sich das WordPress-Menü (inklusive etwaiger Erweiterungen durch Plugins), klont es in eine Property innerhalb meiner Plugin-Klasse und extrahiert dabei schon mal alle Drittanbieter-Menüs in eine separate Property.
  2. replace_menus() – tauscht das vorhandene WordPress-Menü als Ganzes gegen meinen in der Zwischenzeit modifizierten Klon aus.
  3. register_settings_page() – fügt meine eigene Admin-Seite (Add-ons) hinzu, von der aus alle Drittanbieter-Menüs zugänglich sind.
  4. hide_menus() – entfernt jene Drittanbieter-Menüs aus der Navigationsleiste, ohne jedoch die zugehörigen Seiten zu killen.
  5. add_indicator_comments() –fügt den Zähler für zu moderierende Kommentare zum neugeordneten Menü hinzu.
  6. add_indicator_updates() – tut Gleiches mit dem Zähler für ausstehende Updates.
  7. register_settings_styles() – registriert das Stylesheet für die Seite Add-ons.

Zeit und Raum

Die Reihenfolge dieser Aktionen, gesteuert über die Prioritäten-Werte der Actions, ist essenziel: Ich will ja ein komplettes Admin-Menü manipulieren, inklusive aller etwaigen registrierten Erweiterungen.

Also muss ich mich so spät als möglich in admin_menu einhaken, nämlich hoffentlich nach allen Anderen, aber immer noch früh genug, um danach, über den gleichen Hook, mein manipuliertes Menü zurückzuspielen und, wiederum danach und über den gleichen Hook, meine eigene Admin-Seite Add-ons zu registrieren – ganz zuletzt, denn sie muss auf alle vorherigen Änderungen zugreifen können.

Von A nach B

WordPress speichert alle top-level Menüpunkte und ihre Metadaten (slug, Titel, Linktext, Icons usw.) in der gobalen Variablen $GLOBALS['menu']; alle zugehörigen Submenüs werden in einer separaten globalen Variablen $GLOBALS['submenu'] gesammelt.

Um den Beitrag ansatzweise lesbar zu halten, beschränke ich mich bei den folgenden Schilderungen auf das top-level Menü ($GLOBALS['menu']); die Interaktion mit dem Submenü läuft weitgehend identisch, jedoch mit dem einen wichtigen Unterschied, dass das Submenü, im Gegensatz zum numerischen Menü-Array, in einem assoziativen Array steckt.

Top-level Menüpunkte lassen sich grundsätzlich eindeutig anhand ihrer slugs identifizieren. Da es mein erstes Ziel ist, die Menüpunkte von anderen Plugins zu extrahieren, zäume ich den Gaul einfach von rückwärts auf: alles, was nicht Core ist, muss ein Drittanbieter sein.

Nun möchte ich zuerst einmal wissen, welche slugs zum Core gehören. Die haben sich seit 2013 kaum geändert, und wenn da jemals nochmal etwas dazukommt, erfahren wir rechtzeitig davon. Also scheisse ich ganz angstfrei auf Dynamik und schreibe mir einfach mein eigenes Array.

Screenshot: $core_menu

Von hier aus ist die Trennung dieser vordefinierten Core-Menüpunkte von allen anderen (d.h. Drittanbietern) ziemlich trivial:

Screenshot: store_menus()
  • Über den admin_menu Hook hake ich meine Funktion store_menus() in WordPress ein und schnappe mir die globale Variable $GLOBALS['menu'].
  • Diese übergebe ich meiner Helfer-Funktion slice_menus().
Screenshot: slice_menus()
  • slice_menus() iteriert per foreach() über die einzelnen Elemente des globalen, numerischen Arrays – unsere Menüpunkte.
  • Jeder Menüpunkt enthält in sich wiederum ein Array, und jedes dritte Element ($item[2]) dieses Arrays enthält den slug, anhand dessen ich prüfe, ob ein Menüpunkt zum Core Menü gehört, oder eben nicht. (Dass dieser numerische Key tatsächlich den slug enthält, brauche ich nicht zu prüfen – die rigide Architektur des Menüs gibt es schlicht vor.)
  • Wenn der slug nun nicht in meinem vordefinierten Core-Array enthalten ist, muss es sich um ein Drittanbieter-Menü handeln; also füge ich es dem Array meiner Property $thirdparty_menu hinzu, so dass ich später darauf zugreifen kann.
  • Zuletzt gibt slice_menus() das globale Menü unbeschadet zurück, so dass dieses innerhalb der o.g. Funktion store_menus() wiederum in einer eigenen Property $menu landet

Nach der Wiederholung dieser Aktion für das Submenü, habe ich – hurra! – die globalen Menüs fein säuberlich filletiert in vier Properties innerhalb der aktuellen Instanz meiner Klasse:

  • $menu – enthält das komplette globale top-level Menü, wie es in WordPress registriert ist (inklusive aller Drittanbieter-Menüpunkte).
  • $thirparty_menu – enthält ausschließlich alle registrierten Drittanbieter-Menüs.
  • $submenu und $thirparty_submenu – enthalten respektive das globale Submenü bzw. mein extrahiertes Drittanbieter-Submenü.

Neusortierung und teilweise Umbenennung der Menüpunkte

Ausgerüstet mit diesen Properties, baue ich mir nun meinen eigenen Klon des Menüs – ein Array, mit dem ich später das von WordPress gelieferte Menü überschreiben möchte.

Vorher nehme ich noch einen kurzen Umweg über eine weitere Helfer-Funktion menu(), in der ich mir, weil ich faul bin, mein zwischengespeichertes, numerisches Menü-Array in ein (für mich intuitiver zu händelndes) assoziatives Array packe, sowie einige seiner Menüpunkte schon mal inhaltlich ein wenig anpasse.

Screenshot: menus()

So erhalten beispielsweise Posts, Appearance und Settings jeweils eine neue Bezeichnung – Content, Design und Setup – sowie teilweise neue Icons.

Außerdem fliegen Themes und Available Tools raus.
Themes zu installieren, zu löschen, oder zu wechseln erlaubt mir auch der Customizer – wozu also einen extra Menüpunkt daran verschwenden?
Und den Menüpunkt Tools halte ich zwar an sich für sinnvoll, dessen top-level Seite Available Tools hingegen für komplett überflüssig; also fliegt auch diese raus, und der top-level Menü-Link Tools führt stattdessen direkt zu Site Health – meines Erachtens ein wirklich sinnvolles und hoffentlich von vielen Nutzerinnen und Nutzer regelmäßig frequnetiertes Tool, das sich nicht in einem Submenüpunkt zu verstecken braucht.

Nachdem ich meinen Menü-Klon fertig gebaut und modifiziert habe, geht es nun endlich (kleine Referenz an meine Wahlheimat Potsdam) quasi auf die Brücke, zum Agenten-Austausch.

Screenshot: replace_menus()

Mit replace_menus() hake ich mich zum zweiten Mal (und mit höherer Priorität, also später) in den admin_menu Hook ein, baue mir mithilfe meines zuvor nach Herzenslust angepassten assoziativen Helfer-Arrays ein numerisches Menü-Array – ausschließlich Core, keine Drittanbieter! – und überschreibe mit diesem zuletzt den kompletten Inhalt der globalen Variable des WordPress-Menüs. Tadaa! 🎉

Und was ist mit den Drittanbieter-Menüpunkten?

Um diese später auf meiner gesonderten Add-ons Seite abbilden zu können, darf ich sie hier nicht einfach aus dem Menü löschen, sonst sind die zugehörigen Seiten ebenfalls weg. Also packe ich sie temporär erstmal ganz ans Ende meines numerischen Menü-Arrays. Wir kümmern uns in einem Moment um darum …

Die Sache mit den Drittanbieter-Menüs

Als dritte und letzte Interaktion mit dem admin_menu Hook registriere ich nun meine eigene top-level Seite Add-ons. Wie gesagt, dass sie in der obersten Menü-Ebene sitzt, dient momentan hauptsächlich Demo-Zwecken; schlussendlich wäre sie vielleicht unter Setup besser aufgehoben.

Auf dieser Seite baue ich mir nun, mithilfe der Daten aus meinen Properties $thirdparty_menu (ihr erinnert euch?) und $thirdparty_submenu pro Drittanbieter-Menü ein Widget mit einer Menü-Liste des jeweiligen Plugins. Die Links aller bescheideren Plugins, die sich zuvor mit einem Eintrag unter Settings zufrieden gegeben haben, sammle ich alle zusammen in einem weiteren Widget.

Screenshot: Add-ons

Damit die Drittanbieter-Seiten erreichbar bleiben, kann ich deren Menüpunkte erst dann aus dem Menü löschen, wenn sämtliche Aktionen über admin_menu bereits abgeschlossen sind und mein neues Menü fertig da steht.

Also wähle ich für meine vierte Interaktion mit WordPress den später feuernden Hook admin_init, hake mich in diesen mit meiner Funktion hide_menus() nun jedoch so früh als möglich ein, denn für eine Menü-Aktion bin ich in diesem Hook sozusagen schon per se „spät dran“.

Mit einer einfachen foreach()-Schleife iteriere ich über mein Array $thirdparty_menu und entferne alle seine Menüpunkte – richtet an dieser Stelle keinen Schaden mehr an, weil WordPress die zugehörigen Seiten bereits registriert hat.

Screenshot: hide_menus()

Der Rest – das Hinzufügen der Indikatoren für Kommetar-Moderation und Updates, sowie das Stylesheet – ist Kosmetik, die ich euch gerne erspare.

Seid ihr noch da?

Definitiv no hard feelings wer nicht alles bis hierhin gelesen hat. 😉 Ich bin ein rücksichtsloses Monster, das unschuldige #Projekt26 mit 1.500+ Wörtern vollzutexten! 🙈

Aber ich wüsste trotzdem sehr, sehr gerne, was ihr von der ganzen Aktion haltet, wenn ihr euch die Screenshots hier und im vorherigen Beitrag so anseht?

  • Wäre das ein nützliches Plugin für euch?
  • Oder scheiss auf trockenen Nutzen – würde es euch Freude bereiten, in so einem WordPress-Backend zu arbeiten?
  • Habt ihr Verbesserungsvoschläge?
  • Fragen?

Die Kommentare sind offen! Und wer über neue Kommentare und/oder neue Beiträge benachrichtigt werden und/oder vollständigen Code sehen und ausprobieren möchte, ist herzlich eingeladen, sich zu registrieren und seinen GitHub-Namen ins Profil einzutragen – Invite zum Repo folgt!

31 comments

  1. 😍. Krieg ich einen “like” Button unter deine Beiträge? Und einen für Torstens Kommentar gleich dazu.

    Ich habe die letzten 3 Tage 3 elementar wichtige Posts zur Entwicklung von WordPress zur Kenntnis nehmen dürfen. 2 davon im #projekt26.

    Jessicas zur Zukunft von WordCamps (in .de)
    Heathers zu WordPress Governance (oder eben deren Absentia)
    – und auf technischer Ebene ein weiterer großartiger Blick über den bestehenden Tellerrand von Dir. Das beste daran: selbst als non-techie verstehe ich die Ausführungen sogar!

    Freu mich drauf das Plugin mal auf eine Testinstallation zu werfen.

    (Links zu den genannten Publikationen nachträglich hinzugefügt, Amn.d.R.)

    1. Krieg ich einen “like” Button unter deine Beiträge?

      Emoji-Reaktionen vielleicht lieber? 😄 Die sind vielfältiger. Mach’ ein Issue im Repo auf! Ich verspreche nichts, aber weiß schon, wo ich anfangen könnte…

      Und danke!

  2. Vielen Dank für die Führung durch den Code!

    Finde die Idee sehr gut und das aufgeräumte Menü sehr schön anzuschauen. Ein Test des Plugins steht auf meiner Liste, werde mich nach selbigem noch mal mit Eindrücken melden 🙂

      1. Hi Caspar,

        ich habe gerade eben das Dashboard-Plugin (und das Altis-Farbschema) auf meiner Site installiert und freue mich jetzt schon sehr darüber, dass da nur noch eine Handvoll Menüpunkte sind, vielen Dank für die Plugins! ❤

        Ich mache für Sachen, die mir jetzt während der Nutzung auffallen, Issues im Repo auf.

        Viele Grüße

  3. Yay, das würde mich sehr freuen. So ein Admin-Menü wäre nützlich & ein Sesselchen für die Augen 😊
    Sollte Standard werden! Vielen Dank fürs Entwickeln und Vorstellen <3

  4. Hallo Caspar, ich bin durch den WP-Letter auf deine beiden Artikel zum WordPress Admin Menü aufmerksam geworden. Und obwohl ich von Code (als Designerin) keine Ahnung habe, hab ich alles gelesen und finde deine Idee und die konkreten Vorschläge zum (Admin-Menü-aufräumen)-Plugin großartig! Als wp Nutzerin, die Ihren Kunden nicht nur gestaltete und umgesetzte Websites verkauft, sondern Ihnen immer auch einen Zugang zum Admin-Bereich gibt, sollte dieser Bereich doch genau wie auch die ganze Website so strukturiert sein, dass User die wichtigen Hauptmenüpunkte sofort finden. Die »Add-ons« würde ich tatsächlich in »Setup« integrieren – dort würde ich (als Laie) sie inhaltlich vermuten, bzw. von dem Bereich die Finger lassen.
    Ich würde dein Plugin gerne ausprobieren!
    Vielen Dank 😊

    1. Super, Sylvia, das ist genau die Zielgruppe, um die es mir geht. Vielen Dank für dein Feedback! Falls du mit GitHub nicht vertraut bist, halte ich dich gerne per Email auf dem Laufenden, sobald es eine Übersetzung des Plugins ins Deutsche gibt (was ja wahrscheinlich nicht schlecht wäre für deinen Anwedungsfall?).

      1. Wow, Caspar, vielen Dank für deine Antwort.
        Die Möglichkeit, per eMail von dir zu erfahren, wenn es dein Plugin zum Testen gibt, wäre wirklich hilfreich für mich. Übersetzt müsste es für mich selbst noch nicht einmal sein. Das wäre dann vor allem für meine Kunden wichtig.
        Nochmals vielen Dank!

  5. Cool – ich fände es auf jeden Fall interessant, wenn es das als Plugin geben könnte.

    Für ein nächstes Projekt, wo wir mit Leuten arbeiten, die einfach nur Inhalte erstellen können sollen, planen wir Wege zu finden das Admin-Menü zu entschlacken.
    Damit sage ich
    1) I feel you – das Admin-Menü braucht Entschlackung
    2) Ich wäre am Code interessiert
    3) Ist deine Lösung weiter eindampfbar? Ich hab ehrlich gesagt den Code größtenteils übersprungen und frag lieber hier doof nach, statt selbst zu denken: Wenn ich auf andere Weise Menüpunkte raus nehmen:
    a) dann sind sie bei deiner Lösung auch raus, weil das das von WordPress tatsächlich zusammengestellte Menü neu sortiert, ja?
    b) dann bricht deine Lösung nicht?

    Weil es vielleicht für andere auch interessant ist – ein Tool, dass ich in Erwägung ziehen würde wäre Plate von WordPlate: https://github.com/wordplate/plate#readme
    Damit lässt sich ziemlich elegant und einfach Menüpunkte aus dem Menü rausnehmen.

    1. Hallo Sebastian, willkommen! Meine hier vorgestellte Lösung ist ganz bewusst sehr „eigensinnig“ gestaltet und grundsätzlich nicht auf Kompatibilität mit anderen existierenden Plugins für das gleiche Problem ausgerichtet. Wenn dir an einer flexibleren Gestaltung des Menüs liegt, bist du mit Tools wie WordPlate (kenne ich nicht) oder den in meinem ersten Beitrag genannten Lösungen sicher besser beraten.

  6. Oh, wow!
    Haben will.
    ;o)

    Ich hab immer wieder mal am Dashboard rumgeschraubt, weil mich dort Vieles doch sehr nervt. Aber ein so konsequentes und vor allem durchdachtes Ergebnis hatte ich nie.
    Dieses Dashboard würde ich sofort nehmen.

  7. Auch ich lehne mich hier interessiert nach vorne 🙂

    Da ich Kunden i.d.R. telefonisch in «ihr» Backend einweise, sehe ich deren Gesichtsausdruck nicht, wenn sie hören, dass die Inhalte der Seitenleiste(n) unter «Design» zu modifizieren sind … 😀

    Deine Lösung wäre auf jeden Fall mal interessant auszuprobieren.

  8. Mega geile Idee. Finde, dass das echt nötig ist. Vor allem da jeder Pluginhersteller die Menüführung anders bewältigt (mal als eigenen Menüpunkt, mal als Unterpunkt etc.) – auf Dauer kann das echt anstrengend sein.

    Würde mich sehr freuen, wenn ich mir das Projekt auf GitHub mal anschauen könnte!

  9. Ich möchte das Plugin auch gerne testen, habe mich extra dafür hier registriert 🙂

    1. Sorry, die Registrierung hatte ich freigeschaltet, aber dann nicht mehr nach deinem GitHub-Handle geschaut. Invite zum Repo ist jetzt raus!

  10. Im Februar war es etwas zu trubelig, aber jetzt würde ich mir Dein Plugin gerne mal genauer ansehen. Sieht schon mal sehr aufgeräumt aus, Respekt!

    GitHub-Handle habe ich eingepflegt, ich würde mich freuen.

Leave a comment

Your email address will not be published. Required fields are marked *