Websupporter

Vor allem über WordPress.

Ich will einen Button im Absatzblock

Im Dezember kam also mit WordPress 5.0 der neue Block-Editor in den Core von WordPress. In den letzten Tagen habe ich nun endlich Zeit gefunden, einige Blogbeiträge, welche ich schon seit längerer Zeit schreiben wollte, zu schreiben.

Wer meine Posts kennt, der weiß, es geht häufig um irgendwelche Codeschnipselchen, die ich erklären möchte. Dazu brauche ich <code> in meinen Texten.

Vor Gutenberg hatte ich meine Texte tatsächlich in Notepad (beziehungsweise Gedit) verfasst, so dass ich gar nicht weiß, ob man im alten TinyMCE so einfach einen Code-Button hatte, aber ich glaube dort gab es einen. Der Absatz-Block von Gutenberg erlaubt bisher einzig die Textausrichtung zu ändern, sowie Texte kursiv und fett zu setzen, zu verlinken oder durchzustreichen… Warum auch immer. Ein Button um <code> einzufügen wird wohl erst mit WordPress 5.2 kommen.

Nun schreibe ich also meine Beiträge direkt in Gutenberg, dem Block-Editor. Was ich schmerzlich vermisse ist ein Button in der Toolbar des Absatzblocks, mit dem ich schnell und einfach einen Text als <code> auszeichnen kann. Ich könnte natürlich, beziehungsweise habe ich dies auch in den beiden vorangegangenen Beiträgen getan, schnell in die HTML-Ansicht des Blocks wechseln und das selbst machen, aber das ist mühsam.

Wie füge ich einen neuen HTML-Tag zur Toolbar hinzu?

In den letzten Wochen sind einige interessante How To’s erschienen zum Thema, wie man einen Block für Gutenberg schreibt. Eine interessante Serie formt sich gerade drüben beim Thomas von Theme Coder. Auch im WordPress Handbuch gibt es hierzu ein gutes Tutorial.

Gutenberg ist aber letztlich eine ziemlich umfangreiche Software Applikation. Blöcke sind nur ein spezifischer Aspekt der API, welche Entwicklerinnen zur Verfügung gestellt werden, um Gutenberg zu erweitern. In einem Vortrag hatte ich im Juli 2018 versucht, etwas mehr Licht auf andere Aspekte der Gutenberg API zu werfen. Dieser ist zwar auch schon etwas veraltet, aber meiner Meinung nach immer noch recht interessant.

Ich will nun einen Absatzblock, der einen Code-Button hat; Ich könnte einen neuen Block basteln, der letztlich eine Kopie des Absatzblocks ist und diesen neuen Knopf enthält. Das klingt irgendwie nach dem falschen Weg und tatsächlich gibt es auch einen eleganteren.

Die Format API

Für meinen Fall ist es wohl der beste Weg, über die Format API zu gehen. Auch für diese gibt es mittlerweile ein gutes Tutorial im Handbuch. Fett, verlinkt, kursiv, durchgestrichen, im Endeffekt sind dies eigene Formatierungen, welche über die Buttons in der Toolbar angesteuert werden können.

Wenn Ihr in der Console wp.data.select('core/rich-text'); eingebt, seht ihr alle registrieren Formate. Neben den angesprochenen Formaten ist dies noch „Annotation“, ein interessantes Format, welches beispielsweise von Yoast SEO benutzt wird, um Euch bei der Lesbarkeitsanalyse auf Sätze hinzuweisen, die etwas länger geraten sind.

Yoast nutzt das Annotationsformat, um Euch auf lange Sätze aufmerksam zu machen.

Ein Format besteht letztlich aus einem Namen, einem HTML-Tag, und optional einer Klasse oder weiteren HTML-Attributen.

In WordPress lingo, a format is a HTML tag with text-level semantics used to give some special meaning to a text selection.

Gutenberg Handbuch

Diese Formate können im sogenannten RichText-Element verwandt werden. Dieses Element ist zuständig für formatierte Texte. Der Absatzblock enthält ein solches RichText-Element, aber auch beispielsweise die Bildunterschriften bestehen aus einem solchen Element. Das RichText-Element ist also Bestandteil verschiedener Blöcke und wird dann verwendet, wenn man der Autorin die Möglichkeit geben möchte, Texte inline zu gestalten (beispielsweise Textabschnitte kursiv zu setzen).

Man kann nun selbst ein solches Format registrieren und darüber hinaus mit einem edit-Callback versehen. Dieser Callback dient letztlich dazu, eine UI zur Verfügung zu stellen, über welche das Format angesteuert werden kann; genau: Hier kann man man einen Button definieren, welcher dann einen markierten Textabschnitt entsprechend in <code> wrappt.

Doch eventuell schauen wir uns zunächst das komplette Script an. Zunächst müssen wir in PHP natürlich unser neues Javascript entsprechend registrieren:

<?php
/**
 * Plugin Name: Code Button
 * Plugin Author: David Remer
 * Author URI: https://websupporter.net
 * License: GPLv2
 */

add_action(
	'enqueue_block_editor_assets',
	function() {
		wp_enqueue_script(
			'code-button',
			plugins_url( '/js/code.js', __FILE__ ),
			['wp-element', 'wp-editor', 'wp-rich-text']
		);
	}
);

Im Action Hook 'enqueue_block_editor_assets', mit dessen Hilfe Scripte und Styles innerhalb des Gutenberg Kontextes geladen werden können, laden wir also unser neues Script, welches wir in js/script.js speichern. Wir benötigen drei Abhängigkeiten: wp-element, wp-editor, wp-rich-text.

Sehen wir uns nun das eigentliche Script an:


( () => {
    "use strict";
    const button = (props) => {
        return wp.element.createElement(
            wp.editor.RichTextToolbarButton, {
                icon: 'editor-code',
                title: 'Code',
                isActive: props.isActive,
                onClick: () => {
                    const applied = wp.richText.toggleFormat(
                        props.value,
                        { type: 'code-button/code' }
                    )
                    props.onChange( applied )
                }
            });
    }

    wp.richText.registerFormatType(
    'code-button/code', {
        title: 'Code',
        tagName: 'code',
        className: null,
        edit: button
    });
})();

Schauen wir uns zunächst den unteren Bereich an: wp.richText.registerFormatType(). Mit Hilfe dieser Funktion können wir neue Formate registrieren. Da diese Funktion in wp.richText zu finden ist, steht unser Script in Abhängigkeit zu wp-rich-text.

An diese Funktion übergeben wir einen eindeutigen Bezeichner (den Namen) des Formats: code-button/code, sowie ein Objekt mit weiteren Attributen. Dieses Attributeobjekt enthält einen Titel (title), den Namen des HTML-Tags (tagName), den Namen der anzuwendenden Klasse (className, in unserem Fall null, weil wir keinen verwenden), sowie den Callback (edit).

Im Endeffekt registrieren wir also <code> als ein neues Format, welches auf eine Textauswahl im RichText-Element angewandt werden kann.

Wir brauchen noch ein UI

Bisher haben wir uns nur mit dem Format selbst beschäftigt. Doch eine Autorin muss natürlich in der Lage sein, dieses Format auch auf Textabschnitte anzuwenden. Ein Button muss her. Im edit-Callback haben wir die Konstante button gesetzt. Dieser Callback dient genau diesem Zweck. Schauen wir uns diesen also näher an.

An den Callback selbst wird ein props-Objekt übergeben; also einige Informationen. Was wir zurückgeben ist letztlich eine React-Komponente (erinnern wir uns: Gutenberg ist eine React-Anwendung).

Wir geben einen RichTextToolbarButton zurück. Bisher (Stand April 2019) ist dieses noch nicht weiter erklärt im Handbuch. Doch im Endeffekt handelt es sich dabei um einen Button in der Toolbar des RichText-Elements.

Wir weisen diesem neuen Button einen Icon zu, indem wir auf das editor-code-Icon der Dashicons verweisen. Wir könnten dort auch einen eigenen Icon setzen, indem wir hier ein SVG-Icon einsetzen würden. Dies sprengt allerdings den Rahmen dieser kleinen Geschichte. Wenn Ihr schon eines der Tutorials durchgemacht habt, wie man einen Block schreibt und wisst wie man Babel oder Webpack aufsetzt, dann könntet ihr hier einfach ein SVG-Element einsetzen.

Neben dem Icon geben wir dem Button auch einen Titel. Wir definieren darüber hinaus, ob der Button aktiv ist oder nicht (isActive). Diese Information finden wir im props-Objekt unter props.isActive.

Schließlich – und hier passiert nun eigentlich alles Wesentliche – definieren wir noch, was passiert, wenn die Benutzerin auf den Button klickt (onClick). Hier handelt es sich wieder um einen Callback, der eben mit diesem Event ausgeführt wird.

Der Textabschnitt, welcher von der Autorin ausgewählt wurde, findet sich letztlich unter props.value. Dieses Objekt enthält folgende Informationen:

  1. Den Text der Auswahl selbst.
  2. Die Information, wo im Gesamttext die Auswahl beginnt.
  3. Die Information, wo die Auswahl endet, sowie
  4. welche Formate auf diese Auswahl schon angewandt wurden.
{
  end: 33, // Die Endposition der Auswahl
  formats: [], // Die schon angewandten Formate
  start: 10, // Die Startposition der Auswahl
  text: Das ist der Auswahltext // Der eigentliche Text
}

Auf diesen Abschnitt wollen wir nun unser neues Format anwenden (beziehungsweise, falls es schon angewendet ist wieder entfernen). Das bedeutet letztlich müssen wir unser Format dem Objekt hinzufügen:wp.richText.toggleFormat() dient genau dazu. Als ersten Parameter übergeben wir props.value und als zweiten ein Objekt, welches den Formattyp übergibt, nämlich unser code-button/button-Format.

Zurück erhalten wir nun ein Textobjekt, welches dieses Format angewandt hat (oder eben, falls es zuvor schon angewandt wurde, nicht mehr anwendet).

Nachdem wir unser Objekt nun abgeändert haben, müssen wir es zurück an das RichText-Element geben. props bringt dazu einen Callback mit: onChange(). An diesen übergeben wir nun dieses neue Objekt.

Zusammengefasst: Wenn wir also ein neues Format registrieren, können wir mit Hilfe des edit Attributs einen Callback definieren. Der Callback erhält als Parameter im Wesentlichen die aktuelle Textauswahl, sowie eine Funktion, der wir erneut eine Textauswahl zurückgeben. Mit Hilfe von wp.richText.toggleFormat() können wir unser Format auf die aktuelle Textauswahl anwenden und diese dann an onChange() zurückgeben, damit die Auswahl im RichText-Element entsprechend verändert wird.

Eine kleine Nick­lig­keit

Gutenberg kommt bisher nicht ohne den ein oder anderen Bug aus. Letztlich steht die Format API derzeit in Konflikt mit dem Mechanismus zum Einfügen von Texten aus der Zwischenablage.

Das Problem besteht darin: Leute wollen aus den unterschiedlichsten Anwendungen ihre Texte in Gutenberg kopieren. Aus Google Docs, Word, Libre Office, you name it. Doch was macht einen Text fett und lässt in Gutenberg den Fett-Button aufleuchten? <strong>. In einem Google Doc könnte dies <span style="font-weight:bold;"> sein.

Die Entwicklerinnen von Gutenberg mussten deshalb sehr viel Mühen aufwenden, um beim Einfügen von Texten aus anderen Anwendungen diese unterschiedlichen Konnotationen zu vereinheitlichen, so dass der Fett-Button auch in Gutenberg an der richtigen Stelle aufleuchtet.

Wenn ich einen Text einfüge, wird dieser nun zum Beispiel nach <span>-Elementen durchsucht und dann geprüft, ob dieses Element eventuell font-weight:bold; enthält. Die <span>-Information wird letztlich weggeschmissen und sollte der Text fett sein, wird er statt dessen in <strong> gewrappt.

Dieser Mechanismus berücksichtigt derzeit noch keine Formate, welche über registerFormatType() registriert wurden. Möchtet Ihr also ein Format registrieren, welches auf der „schwarzen Liste“ steht (<span>, <b>, <i>) und eine Autorin möchte den Text, welchen Sie in Gutenberg geschrieben hat, und welches beispielsweise <span class="highlight">toller Text</span> enthält in einen anderen Absatz kopieren, so wird der tolle, kopierte Text nicht mehr von einem <span> Element gewrappt sein.

Dieses Video veranschaulicht, was ich meine:

copy error with custom formats

Click the button below to load the content from Youtube.

Der „Haus“-Button enthält ein kritisches Format. Wir sehen, dass der Textabschnitt rot wird, wenn man den Button klickt. Wird nun jedoch genau dieser Text in die Zwischenablage gelegt und wieder einkopiert, verschwindet das Format leider. Das Problem ist bekannt und wird sicherlich früher oder später behoben werden. Derzeit besteht es allerdings noch.

Über den Autoren

Seine erste Webseite hat David Remer 1998 in HTML verfasst. Wenig später war er fasziniert von DHTML und JavaScript. Heute konzentriert sich vor allem auf das Entwickeln von WordPress Themes und Plugins für Inpsyde. Außerdem hat er das Buch "WordPress für Entwickler" verfasst.

Kommentare

  1. Hi David,

    Vielen Dank für den Hinweis auf meine Artikelreihe und den interessanten Einblick in die Format API von Gutenberg. Die war mir bis dato noch gar nicht richtig bekannt.

    Der Code-Button fehlt mir persönlich ebenfalls im Editor. Hast du vor, das Feature als fertiges Plugin auf Github oder WordPress.org anzubieten? Das wäre großartig 🙂

    Viele Grüße,
    Thomas

    1. Danke 🙂

      WordPress 5.2 wird den Code-Button haben. Das aktuelle Gutenberg Plugin hat ihn auch. Wusst ich natürlich nicht, als ich meinen Code-Button geschrieben hatte :facepalm:

      Aber als Tutorial eignet sich der Beitrag ja trotzdem, deshalb hatte ich das so gelassen XD

  2. Hallo,

    das TinyMCE hat den Code Button auch. Das uns der Gutenberg Editor aufgezwungen wurde ist eine Frechheit. Ich musste mir das den Classic Editor als Plugin installieren, weil ich Seo Yoast nutze, das verträgt sich nicht mit Gutenberg.
    Ich hätte ihn aber sonst auch nicht haben wollen.
    Das TinyMCE finde ich ganz gut und gegenüber Gutenberg bestimmt nicht alt.
    Was mich aber an TinyMCE, Seo Yoast WP Cleaner u. s. w. stört ist, dass die Beschreibungen zu den Funktionen in oft in Denglisch geschrieben sind. Auch die unsinnigen Beschreibungen, die mit, wenn du denkst, dass diese Funktion, oder wenn du weißt, was du tust,anfangen.

    Hey, ich weiß nicht, was ich tue, ich habe keine Ahnung von dem Plugin, deshalb lese ich die Beschreibung.
    Das ist nicht userfreundlich und jenseits von professionell.

    1. Hi TinyWinyFTS,
      danke für Dein Feedback. Ui, da weiß ich gar nicht wo ich anfangen soll 😀

      Für Fans vom TinyMCE waren die letzten Monate bestimmt kein Spaß!

      Ich musste mir das den Classic Editor als Plugin installieren, weil ich Seo Yoast nutze, das verträgt sich nicht mit Gutenberg.

      Das ist interessant. Ich benutze ebenfalls Yoast und habe da keine Probleme mit der Kombination.

      Was mich aber an TinyMCE, Seo Yoast WP Cleaner u. s. w. stört ist, dass die Beschreibungen […] oft in Denglisch geschrieben sind.

      Hmm… Ich selbst stolpere nicht so häufig über solche Probleme, es kann aber auch sein, dass ich mich an so etwas schon gewöhnt habe oder so. Was Übersetzungen generell angeht gibt es einen Glossar, nach welchem Übersetzungen von zahlreichen Freiwilligen hier erstellt werden. Da finden sich tatsächlich einige englische Begriffe auch als Übersetzung wieder, wie beispielsweise „Backend“ oder „Button“. Ich vermute, dass man sich bei diesen Begriffen einfach gedacht hat, dass sie sich schon ziemlich stark eingebürgert haben im Umgang mit dem Internet, so wie beispielsweise „userfreundlich“. Aber vielleicht meinst Du auch etwas anderes.

      Auch die unsinnigen Beschreibungen, die mit, […] wenn du weißt, was du tust, anfangen. Hey, ich weiß nicht, was ich tue, […] deshalb lese ich die Beschreibung.

      Ha ha. Die Beschreibungen kenne ich auch XD

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.