Kategorien
Gutenberg JavaScript

HTML Code in Blöcke umwandeln und in den Gutenberg Editor einfügen

Wie wir Blöcke im Gutenberg Editor bearbeiten und löschen habe ich bereits in einem vergangenen Beitrag beschrieben. Heute soll es darum gehen wie wir aus HTML-Markup Blöcke erstellen und diese in den Editor einfügen können.

Mit Hilfe der Data API, können wir Blöcke in den Gutenberg Editor einfügen. Das Problem dabei ist nur, dass wir auf irgendeinem Weg die Blöcke erstellen müssen. Der einfachste Weg ist HTML Code in Blöcke umzuwandeln.

HTML in Blöcke umwandeln

Hierfür nutzen wir die Funktion wp.blocks.rawHandler()

Diese Funktion nimmt ein JavaScript Object, als Parameter entgegen.

const { rawHandler } wp.blocks;

const htmlMarkup = '<h2>My Headline</h2><ul><li>Item 1</li><li>Item 2</li></ul>';

const newBlocks = rawHandler({HTML: htmlMarkup});

Blöcke in den Editor einfügen

Nachdem wir jetzt in der Konstante newBlocks unsere Blöcke gespeichert haben, können wir diese in den Editor einfügen.

Mit der Action insertBlocks() können wir die Blöcke einfügen.

wp.data.dispatch('core/editor').insertBlocks(
    blocks,
    index,
    rootClientId,
    updateSelection
) 

Nur der erste Parameter ist notwendig, alle anderen sind optional.

Der erste Parameter nimmt die Blöcke, die wir gerade aus dem HTML Code generiert haben entgegen.

Der zweite Parameter index legt fest, an welcher Stelle wir die Blöcke einfügen möchten. Um die Blöcke am Anfang des Editors einzufügen verwenden wir den Index 0, um sie an der zweiten Position einzufügen verwenden wir den Index 1. Wenn wir den Parameter leer lassen, werden die Blöcke am Ende des Beitrags eingefügt.

Der Dritte Paramter rootClientId können die Blöcke in einen anderen Block, z.B. in einen Spalten-Block eingefügt werden. Hierfür muss die Client ID eines Blocks angegeben werden. (mehr Infos in meinem anderen Beitrag)

Der vierte Parameter updateSelection nimmt true oder false entgegen und regelt, ob nach dem Einfügen der Blöcke, der erste eingefügte Block selektiert sein soll oder nicht. Standard ist true.

Im gesamten sieht unser Code so aus:

const { rawHandler } = wp.blocks;
const { dispatch } = wp.data;

const htmlMarkup = '<h2>My Headline</h2><ul><li>Item 1</li><li>Item 2</li></ul>';

const newBlocks = rawHandler({HTML: htmlMarkup});

dispatch('core/editor').insertBlocks(
    newBlocks,
    1
);

Weitere Funktionen im Blöcke in den Gutenberg Editor einzufügen.

Nebem der insertBlocks Action gibt es – je nach Anwendungsfalls – weitere Möglichkeiten um Blöcke in den Editor einzufügen.

  • replaceBlocks() zum ersetzen/überschreiben von Blöcken
  • replaceInnerBlocks() zum erstetzen/überschreiben von Child-Blöcken
  • resetBlocks() um alle Blöcke im Editor zu überschreiben.

Weitere Informationen

Der core/editor Data Store im Gutenberg Handbook.

Kategorien
JavaScript Plugins

React im Frontend eines Gutenberg Blocks verwenden

Gutenberg und die Gutenberg Blöcke verwenden im Backend React zum Rendern des Editors. Im Frontend hingegen, wird meist auf jQuery gesetzt.

Wir können React aber auch im Frontend der Seite nutzen und dabei sogar Elemente aus dem Backend wiederverwenden.

React im Frontend laden

Zuerst müssen wir unser JavaScript im frontend laden und die WordPress React Library [ 'wp-element'] als Dependencies benennen.

$frontend_js_path = "/assets/js/filters.frontend.js";
wp_enqueue_script( 
	"gutenberg-code-highlighter-frontend",
	_get_plugin_url() . $frontend_js_path,
	[ 'wp-element'],
	filemtime( _get_plugin_directory() . $frontend_js_path ),
	true
);

Dadurch können wir in unserem JavaScript Code über wp.element auf die Element Library von WordPress zugreifen. Diese ist einen Wrapper für die eigentliche React Library.

Sofern wir auf weitere Libraries im Frontend zugreifen möchten, können wir diese ebenfalls in den Dependencies aufführen.

Das könnten z.B. sein:

  • wp-i18n für die Übersetztung / Lokalisierung
  • wp-api-request um auf die REST-API zuzugreifen
  • wp-components zum wiederverwenden von Gutenberg Components

React in unserem Code laden

In unserem Frontend JavaScript Code laden wir zuerst die render Funktion von React

const { render } = wp.element;

Anschließend durchsuchen wir die Seite nach unseren Blöcken – wir möchten in diesem Beispiel den core/code Block modifizieren – und erstellen einen Loop.

const codeElements = document.querySelectorAll( ".derweili-gutenberg-code-highlighter" );

codeElements.forEach( ( codeElement, index ) => {

});

Innerhalb des Loops nutzen wir die render Funktion um einen React Component an der Stelle des Blocks zu laden.

Im Gesamten sieht das dann so aus:

const { render } = wp.element;

import Highlight from 'react-highlight.js'


const codeElements = document.querySelectorAll( ".derweili-gutenberg-code-highlighter" );

codeElements.forEach( ( codeElement, index ) => {
    
    const language = codeElement.dataset.language;
    const code = codeElement.getElementsByTagName( 'pre' )[0].childNodes[0].innerText;

    render(
        <Highlight language={language}>
            {code}
        </Highlight>,
        codeElement
    );

});

Verwendet habe ich das in meinem Syntax Highlighter Plugin das Ihr auf Github finden könnt:

https://github.com/derweili/gutenberg-code-highlighter/

Kategorien
Gutenberg JavaScript

Datum und Uhrzeit in Gutenberg formatieren

Wer Plugins und Themes für WordPress entwickelt, kennt sicher die PHP Funktionen, die WordPress für die Formatierung von Datum und Uhrzeit bereitstellt.

Was im Support Artikel auf WordPress.org nicht steht, ist dass WordPress ein paar dieser Funktionen im Gutenberg Editor auch für JavaScript bereitstellt.

Darauf zugreifen können wir über wp.date

const { date } = wp

Folgende Funktionen stehen uns zur Verfügung:

  • date(format, timestamp) entspricht der php date() Funktion
  • dateI18n() entspricht der date_i18n() WordPress Funktion
  • format( dateFormat, value ) gibt das aktuell Datum im angegebenen Format aus
  • getDate() Gibt das aktuelle Datum aus
  • gmdate() Entspricht gmdate() in PHP
  • isInTheFuture( date ) gibt true oder false zurück, abhängig davon ob das angegebene Datum in der Zukunft liegt.
  • setSettings()

Die dazugehörige Dokumentation im Gutenberg Handbook findet ihr hier:

Kategorien
Gutenberg JavaScript

Notices in Gutenberg erstellen

Der Gutenberg Editor bringt mit den Notices einem Benachrichtigungssystem mit sich, mit dem Erfolgs-, Fehler-, oder sonstige Meldungen ausgegeben werden können.

Eine solche Notice sieht zum Beispiel so aus:

Gutenberg Benachrichtigung

In der nächsten WordPress Version kommen die sogenannten „Snackbar“-Notices dazu, die so aussehen:

Wer diese testen möchte, kann sich das aktuelle Gutenberg Plugin installieren. Mehr Infos zu den „Snackbar“ Notices findet Ihr im Artikel von WP Tavern

Das Benachrichtigungssystem von Gutenberg können wir auch für unsere Blöcke und Gutenberg Erweiterungen nutzen können.

Eigene Notice erstellen

Notices werden über den core/notices Data Store verwaltet.

Die Basis zum Erstellen von Notices ist diese Funktion:

wp.data.dispatch('core/notices').createNotice( status, content, options)

Notice status

Der erste Parameter gibt die Art der Benachrichtigung an. Der Standardwert ist info

Weitere möglich Werte sind:

  • success
  • error
  • warning

Je nach Status, werden die Benachrichtigungen grün (success), rot (error), orange (warning) oder blau (info) dargestellt.

Notice content

Beim zweiten Parameter handelt es sich um die eigentliche Nachricht.

Der content Parameter nimmt ein string entgegen.

Notice options

Der options parameter ist optional und nimmt ein Objekt entgegen.

Folgende Optionen gibt es:

id

Die ID wird verwendet um die Notice später identifizieren zu können, um sie beispielsweise zu löschen oder zu überschreiben.

Wenn die ID nicht manuell festgelegt wird, wird sie automatisch generiert.

Wird eine ID festgelegt, die bereits in Verwendung ist, wird die bestehende Notice überschrieben.

isDismissible

Gibt an ob der Nutzer die Benachrichtigung ausblenden kann. Kann true oder false sein.

speak

Gibt an ob die Nachricht auch an Screenreader gesendet werden soll. Ist im Standard true.

Der Wert kann true oder false sein.

actions

Hierüber können Aktionen definiert werden, über die der Nutzer mit der Benachrichtigung interagieren kann.

Muss ein Array aus Objekten enthalten sein. Jedes Objekt stellt eine Aktion dar und muss wiefolgt aufgebaut sein:

{
    url: '#',
    label: 'View post'
}

type

Hierüber wird geregelt ob die Benachrichtigung als „Standard Benachrichtigung“ (siehe Screenshot) oder als Snackbar Notice ausgegeben werden soll.

Kann entweder den Wert 'default' oder 'snackbar' haben.

Beispielcode für eine Snackbar Notice

const { dispatch} = wp.data;

dispatch( 'core/notices' ).createNotice(
    'info',
    __('Template selected', 'block-layouts'),
    {
        isDismissible: true,
        type: 'snackbar'
    }
)

Weitere Funktionen zum Erstellen von Notices

Zusätzlich zur createNotice() gibt es weitere Funktionen, mit denen Notices erstellt werden können.

Diese unterscheiden sich zur createNotice() Funktion darin, dass der erste Parameter entfällt. Mit der Auswahl der Funktion wird gleichzeitig der Status der Notice definiert.

Folgende weitere Funktionen gibt es:

  • createErrorNotice() zum Erstellen von Error Notices
  • createInfoNotice() zum Erstellen von Info Notices
  • createSuccessNotice() zum Erstellen von Success Notices
  • createWarningNotice() zum Erstellen von Warning Notices

Notice Löschen

Um eine Notice zu löschen verwenden wir die Funktion

wp.data.dispatch('core/notices').removeNotice(id);

Dieser Funktion übergeben wir die ID der zuvor erstellten Notice. Diese ID kann beim Erstellen über das options Objekt definiert werden.

Wenn wir keine ID festgelegt haben, wurde der Notice automatisch eine ID zugewiesen. In diesem Fall müssen wir erst die IDs der Notices auslesen.

Aktive Notices ausgeben

Um alle aktuell vorhandenen Notices auszulesen verwenden wir den einzigen Selektor, den uns der core/notices Data Store bereitstellt:

wp.data.select('core/notices').getNotices();

Als Rückgabewert erhalten wir ein Array mit WPNotice Objekten.

Weitere Informationen

Kategorien
Gutenberg JavaScript

Blöcke über JavaScript bearbeiten und löschen

Gutenberg bietet uns mit dem Data Modul die Möglichkeit Blöcke im Editor zu bearbeiten.

Auf das Data Modul, können wir über wp.data zugreifen.

Dieses Modul enthält verschiedene Funktionen von denen wir hier zwei näher anschauen werden. Wir benötigen wp.data.select() zum Auslesen des Ist-Zustands der Blöcke und wp.data.dispatch() zum ausführen von Aktionen, z. B. zum Löschen oder Bearbeiten eines Blocks.

Das Data Modul ist aufgeteilt in verschiedene Data Stores, die jeweils den Status eines bestimmten Bereichs von Gutenberg verwalten.

Da wir zum Erstellen, Bearbeiten und Löschen von Blöcken den core/editor Data Store benötigen, verwenden wir also wp.data.select('core/editor') bzw. wp.data.dispatch('core/editor').

Bevor wir Blöcke bearbeiten können, müssen wir in der Regel erst den aktuell Zustand der Anwendung kennen.

Selectors

Über die wp.data.select('core/editor')erhalten wir Zugriff auf alle wichtigen Funktionen (Selectors) mit denen wir den aktuellen Zustand der im Editor vorhanden Blöcke auslesen können.

Eine Übersicht aller verfügbaren Funktionen findest du im Gutenberg Handbook

Alle Blöcke ausgeben

wp.data.select( 'core/editor' ).getBlocks();

Mit der getBlocks(); Funktion erhalten wir alle im Editor vorhanden Blöcke in einem Array zurück.

Beispiel Rückgabewert:

0:
    attributes:
        content: "Gutenberg bietet uns mit dem <a href="https://developer.wordpress.org/block-editor/data/">Data Modul</a> die Möglichkeit, Blöcke die sich sich im Editor befinden, zu manipulieren."
        dropCap: false
        __proto__: Object
    clientId: "1d066448-190b-4f0a-a495-b43ece88966d"
    innerBlocks: Array(0)
        length: 0
        __proto__: Array(0)
    isValid: true
    name: "core/paragraph"
    originalContent: "<p>Gutenberg bietet uns mit dem <a href="https://developer.wordpress.org/block-editor/data/">Data Modul</a> die Möglichkeit, Blöcke die sich sich im Editor befinden, zu manipulieren.</p>"
    __proto__: Object
1:
    attributes:
        content: "Das Data Modul basiert auf redux, einer JavaScript Bibliothek zur Verwaltung Zustandsinformationen in einer Webanwendung."
        dropCap: false
        __proto__: Object
    clientId: "1bfbdffa-ad42-4518-8b90-1878df58236f"
    innerBlocks: Array(0)
        length: 0
        __proto__: Array(0)
    isValid: true
    name: "core/paragraph"
    originalContent: "<p>Das Data Modul basiert auf redux, einer JavaScript Bibliothek zur Verwaltung Zustandsinformationen in einer Webanwendung.</p>"
        __proto__: Object
…
6:
    attributes:
        content: "Selectors"
        level: 2
        __proto__: Object
    clientId: "4eba91d3-9343-4e09-8939-07bd26f89c9d"
        innerBlocks: Array(0)
        length: 0
        __proto__: Array(0)
    isValid: true
    name: "core/heading"
    originalContent: "<h2>wp.data.select('core/editor')</h2>"
    __proto__: Object

Bei den hier zu sehenden Daten, ist besonders die Client ID zu beachten. Jeder Block erhält beim Einfügen in den Editor eine individuelle ID.

z.B. „167affeb-c437-4a6f-b0e2-71b2fc68a617“

Diese ID benötigen wir später um die Blöcke zu bearbeiten.

Selektierten Block ermitteln

Um zu ermitteln ob ein Block gerade selektiert ist, verwenden wird die Funktion

wp.data.select('core/editor').isBlockSelected(clientId);

Der Funktion übergeben wir die gerade erwähnte clientId als Paramerter. Als Rückgabewert erhalten wir entweder true, wenn der Block gerade im Editor selektiert ist, oder false wenn er es nicht ist.

Actions

Über wp.data.select('core/editor')erhalten wir Zugriff auf Funktionen, mit denen wir die Blöcke im Editor bearbeiten können.

Mit diesen Funktionen können wir Blöcke löschen, bearbeiten, einfügen und ersetzen. Eine Über alle verfügbaren Funktionen findest du in Gutenberg Handbook

Einen Block löschen

Um einen Block zu löschen verwenden wir die Funktion removeBlock( clientId )

wp.data.dispatch( 'core/editor' ).removeBlock( clientID );

Als Parameter übergeben wir der Funktion die oben genannte Client ID des zu löschenden Blocks.

Block Attribute bearbeiten

wp.data.dispatch( 'core/editor' ).updateBlockAttributes( id, attributes )

Mit der updateBlockAttributes Funktion können wir die Attributes eines Blocks bearbeiten. Die Funktion benötigt zwei Parameter, die Block ID und die Attribute die wir ändern möchten.

Um die Ebene einer Überschrift (h1,h2,h3,etc) zu ändern verwenden wir folgenden Code:

const { dispatch } = wp.data;

dispatch( 'core/editor' ).updateBlockAttributes(
	"80a3889a-680e-44fe-9fa5-813e8d5b59be",
	{level:3}
);

Um den Inhalt eines Absatz-Blocks zu ändern verwenden wir folgenden Code:

const { dispatch } = wp.data;

dispatch( 'core/editor' ).updateBlockAttributes(
	"242d7a78-1047-47af-9dc9-83c32809b2a4", 
	{content:'Lorem Ipsum …'}
);

Blöcke einfügen

Blöcke können wir über die Funktion: insertBlock( block, index, rootClientId, updateSelection) eingefügt werden.

wp.data.dispatch('core/editor').insertBlock()

Wie genau diese Funktion verwendet wird, werde ich in einem kommenden Beitrag erklären

Kategorien
Gutenberg Plugins

Mein neues Plugin: Block Layouts

Nachdem ich jetzt schon seit 1,5 Jahren mit den Gutenberg Editor arbeite, ist mir aufgefallen, dass ich immer wieder die selben Blöcke, in der selben Kombination verwende, es aber keine Möglichkeit gibt, diese Layouts wiederzuverwenden. Klar, gibt es die „wiederverwendbaren Blöcke“, ich möchte aber nicht immer den selben Inhalt, sondern nur die selben Elemente verwenden.

Aus anderen Programmen kenne ich solche Funktionen. In PowerPoint gibt es die Masterfolien und in InDesign gibt es die Musterseiten

Ich machte mich also auf die Suche, nach einer ähnlichen Funktion im Gutenberg Editor und bin auf die Funktion der Block-Templates gestoßen.

Block Templates

Mit Block Templates kann ich als Plugin Entwickler festlegen, welche Blöcke ein Beitrag haben soll, wenn der Nutzer einen neuen Post erstellt.

Das ist schonmal eine tolle Sache und bei einigen Plugins habe ich das auch schon gesehen, z. B. beim The Events Calendar Plugin. Wenn du wissen möchtest, wie man diese Block Template erstellt, findest du im Blog von Florian Brinkmann eine tolle Anleitung.

Leider sind die Block Templates nicht ganz das wonach ich suchte, denn sie haben ein paar Nachteile:

  • Sie sind Post-Type Spezifisch
  • Sie können nicht über das WordPress Backend verwaltet werden
  • Für jeden Post-Type kann nur ein Template definiert werden.

Ich suchte weiter, fand aber keine bestehende Lösung, die meine Anforderungen erfüllte. Daher entschied ich mich, meine eigene Lösung zu entwickeln.

Herausgekommen ist mein neues Plugin:

Block Layouts

Das Block Layouts Plugin bietet dir die möglichkeit über das WordPress Backend eigene Layouts (Tempaltes) zu definieren und diese für alle Inhaltstypen wiederzuverwenden.

Du kannst eine beliebige Anzahl an Layouts erstellen. Beim Anlegen einer neuen Seite oder Beitrag kannst du aus den Layouts wählen.

Layouts erstellen

Nachdem du das Plugin installiert und aktiviert hast, findest du im Menü den Menüpunkt „Block Layouts“. Dort findest du alle vorhandenen Layouts. Über den „Erstellen Button“ kannst du neue Layouts erstellen.

Die Layouts kannst du einfach über den Gutenberg Editor bearbeiten.

Wenn du Bereiche für Bilder oder Videos festlegst, empfehle ich nur den jeweiligen Block einzubauen, und noch kein Bild oder Video auszuwählen. Das erzeug später eine Ähnliche Funktionalität wie wir sie von den PowerPoint Masterfolien kennen.

Bevor du das Block Layout veröffentlichst, solltest du noch ein Beitragsbild auswählen. Dieses Beitrags Bild ist genauso wie die Block Layouts nicht öffentlich sichtbar, es dient dir aber zur schnelleren Wiedererkennung des Layouts. Am Besten nimmst du dafür ein Icon.

Wenn du also ein Layout für einen Rezept erstellst, kannst du ein Icon verwenden, das Messer und Gabel zeigt. Wenn du ein Musikreview Template erstellst, nimm doch einfach Noten.

Layouts verwenden

Um Layouts jetzt verwenden, erstellst du einfach eine neue Seite oder einen neuen Beitrag. Im daraufhin erscheinenden Edit-Screen öffnet sich ein Modal in dem du das Template auswählen kannst.

Wähle das Template das du verwenden möchtest aus und starte mit der Bearbeitung deines Beitrags.

Block Layouts später zuweisen oder ändern

Um das verwendete Layout später zu ändern oder um ein anderes Layout zuzuweisen, gibt es die Block Layouts Sidebar.

Diese findest du im Optionen Menü (Icon mit den drei Punkten)

Die Block Layouts Sidebar

In dieser Sidebar findest du alle verfügbaren Layouts. Bei Klick auf ein der Layouts wird dieses auf die aktuelle Seite angewendet.

Achtung: dein gesamter Beitrag wird dadurch überschrieben.

Kategorien
Allgemein Gutenberg JavaScript

Wieso eigene Gutenberg Blöcke nicht immer die Lösung sind.

Bei der Entwicklung und Erweiterung des neuen Gutenberg Editors in WordPress dreht sich aktuell alles darum, wie man eigene Blöcke erstellen kann. Es scheint als würde jeder seinen eigenen mehr oder weniger sinnvollen Block erstellen.

Block Libraries

Ganze Block Libraries wie z.B. „Atomic Blocks“ werden so aktuell entwickelt. Diese beinhalten eine Reihe Vielzahl an Blöcken, von denen man meist nur wenige benötigt.
Oft beinhalten diese Libraries sogar Blöcke, die in ähnlicher Form bereits im Gutenberg Standard vorhanden sind. Statt diese standard Blöcke zu verändern, werden immer mehr neue Blöcke erstellt. Beispielsweise bietet Atomic Blocks Blöcke wie den „Container Block“ (entspricht dem Group Block) oder den Spacer & Divider (ähnlich dem „Abstandshalter Block)

Das Problem

Mir stellt sich daher die Frage wie nachhaltig dieses vorgehen ist. Was passiert, wenn diese Block Libraries in ein paar Jahren nicht mehr weiterentwickelt werden? Gutenberg erlebt gerade eine so schnelle Entwicklung, Funktionen werden geändert und die Plugin Entwickler müssen bei diesen Änderungen mithalten.

Was aber, wenn der Entwickler die Lust verliert?

Wenn diese Block Libraries nicht mehr kompatibel zu neusten Gutenberg Version sind, kann Gutenberg den HTML Coder nicht mehr in Blöcke umwandeln und es kommt zu Validierungsfehlern ähnlich diesem hier:

Der in diesen Blöcken vorhandene Inhalt ist also verloren.

Wenn wir eine Website erstellen möchten, die auch in ein paar Jahren noch existieren und editierbar sind soll, sollten wir diese Libraries und sonstigen Plugins, die eigene Blöcke mit sich bringen, nur Vorsicht einsetzten.

Gibt es Alternativen?

Natürlich gibt es viele Anwendungfälle in denen eigene Blöcke sinnvoll und vermutlich auch auch der einzige Weg sind, um zum gewünschten Ergebnis zu kommen. Ich habe in einem meiner neusten Projekte selbst 8 verschiedene Custom-Blöcke erstellt.

Bevor wir aber unseren eigenen Block entwickeln, nur um z.B. eine andere Galerie-Ansicht zu realisieren, sollten wir uns überlegen welche Alternativen wir haben.

Gutenberg bietet eine Reihe von Erweiterungmöglichkeiten. Aber auch hierbei bei diesen müssen wir immer darauf achten, dass wir keine Änderungen vornehmen, die wir nicht rückgängig machen können.

Welche Möglichkeiten haben wir also?

CSS Anpassungen

Für einfache Änderungen, reichen Anpassungen der Stylesheets oft aus. Schau dir das HTML Markup der Blöcke an, dieses bietet mehr Darstellungsmöglichkeiten, als die Standardansicht.

Beispiel Bildergalerie:

Du möchtest, dass die Caption nicht auf, sondern unter dem Bild liegt?

Dafür reichen ein paar Zeilen CSS:

.wp-block-gallery .blocks-gallery-item figure {
    display: flex;
    flex-direction: column;
}

.wp-block-gallery .blocks-gallery-item figcaption {
    position: relative;
    color: black;
    background: transparent;
}

Auch aufwändiger Galerielayouts, wie ein horizontales Masonry Grid sind über reine CSS Anpassungen möglich:

Block Rendering im Frontend manipulieren

Es gibt natürlich Fälle, in denen die Anpassungen via CSS nicht ausreichen. Dies ist der Fall, wenn wir zwar eine Galeriefunktion haben, im Frontend aber einen ander HTML Struktur benötigen, z.B. um einen Bilderslider darzustellen.

Für diesen Anwendungsfall bietet uns Gutenberg den render_block Filter. Diesen Filter durchlaufen alle Blöcke, bevor sie im Frontend ausgegeben werden.

Der Filter besitzt bietet Parameter, $block_content und $block.

Der erste Parameter ist das unveränderte HTML Markup, das im Frontend ausgegeben wird. Der zweite Parameter enthält alle Attribute des Blocks strukturiert in einem Array.

 add_filter( 'render_block', 'derweili_modify_gallery_block', 10, 3);
 function derweili_modify_gallery_block( $block_content, $block ) {

     // only modify the Gallery Block
     if( "core/gallery" !== $block['blockName'] ) {
         return $block_content;
     }

     return $block_content;

}

Bevor wir einen Block manipulieren, müssen wir prüfen um welchen Block es sich handelt, da alle Blöcke diesen Filter durchlaufen. Dies tun wir, indem wir $block['blockName'] auslesen.

Anschließend können wir wir den Block nach belieben verändern. Z.B. können wir den Block mit einer Galerie umschließen:

 add_filter( 'render_block', 'derweili_modify_gallery_block', 10, 3);
 function derweili_modify_gallery_block( $block_content, $block ) {

     // only modify core code block
     if( "core/gallery" !== $block['blockName'] ) {
         return $block_content;
     }

     $output = '<div class="gallery-wrapper">';
     $output .= $block_content;
     $output .= '</div>';

     return $output;
 }

Wir können aber auch das komplette Markup neu schreiben. Dafür finden wir im $block['attrs']['ids'] Array die IDs der in der Galerie enthaltenen Bilder. Diese können wir dann z.B. so verwenden um einen Slider zu erzeugen:

 add_filter( 'render_block', 'derweili_modify_gallery_block', 10, 3);
 function derweili_modify_gallery_block( $block_content, $block ) {

     // only modify core code block
     if( "core/gallery" !== $block['blockName'] ) {
         return $block_content;
     }

     $output = '<div class="slider">';
     foreach ($block['attrs']['ids'] as $img_id) {
       $output .= '<div class="slide">';
       $output .= wp_get_attachment_image( $img_id, 'large' );
       $output .= '</div>';
     }
     $output .= '</div>';

     return $output;
 }

Der Vorteil des „render_block“ Filter ist, dass dieser nur die Ausgabe im Frontend modifiziert. Es werden keine an der Datenstruktur des Blocks vorgenommen. Block-Validierungsfehler sind damit ausgeschlossen.

Die Block Edit Funktion bearbeiten

Es gibt aber auch Fälle in denen wir den Block Editor bearbeiten möchten. Z.B. um dem Block weitere Einstellungen (Inspector Controls) hinzuzufügen.

Dafür gibt es React Filter, die ähnlich den Filtern in PHP funktionieren. Wir benötigen zwei davon. Zu erst müssen wir die vom Block unterstützten Attribute erweitern.

Anschließend müssen wir die entsprechenden UI Elemente hinzufügen.

Block Attribute erweitern

Über die Funktion addFilter können wir in React auf Filter zugreifen. Diese Funktion benötigt drei Paremeter.

  1. Den Filter, den wir nutzen wollen
  2. Einen Namespace für unsere Anpassung
  3. Die Callback-Funktion mit der wir Anpassungen vornehmen

Die Callback Funktion nimmt ebenfalls zwei Parameter entgegen.

  1. Das Settings Array (entspricht dem Settings Array der registerBlockType Funktion
  2. Den Block Name
addFilter(
    "blocks.registerBlockType",
    "gutenbergcodehighlighter/code-attributes",
    addCodeAttributes
)

function addCodeAttributes( settings, name ){

    // only filter code block
    if("core/code" !== name ) return settings;

    settings.supports = lodash.merge({}, settings.supports, {
        align: ["full", "wide"]
    });

    // do something with the settings
    settings.attributes.align = {
        type: "string",
        default: "wide"
    }

    return settings;

}

Zuerst überprüfen wir wieder, um welchen Block es sich handelt, danach modifizieren wir die Settings und geben diese zurück.

In diesem Beispiel erweitern wir den Code Block um ein full/wide Alignment und stellen dieses im Standard auf „wide“.

Block Edit erweitern

Im Grunde könnten wir im oben genannten Code auch die Edit Funktion erweitern/ersetzen. Das bringt aber einige Probleme mit sich, weshalb es einen zweiten Filter gibt, den editor.BlockEdit Filter.

Hier ein Auszug aus meinem Code Highlighter Plugin:

function addCodeInspectorControls( BlockEdit ) {

    const withInspectorControls =  createHigherOrderComponent( BlockEdit => {

        return props => {
            if( "core/code" !== props.name ) return <BlockEdit {...props} />;

            return (
                <Fragment>
                    <InspectorControls>
                        <PanelBody title={__("Language", 'gutenberg-code-highlighter')}>
                            <PanelRow>
                            <RadioControl
                                label="Language"
                                help="Language of your Code"
                                selected={ props.attributes.language }
                                options={ [
                                    { label: 'Default', value: '' },
                                    { label: 'PHP', value: 'php' },
                                    { label: 'JavaScript', value: 'javascript' },
                                    { label: 'JavaScript ES6', value: 'es6' },
                                    { label: 'HTML', value: 'html' },
                                    { label: 'CSS', value: 'css' },
                                    { label: 'SASS', value: 'sass' },
                                    { label: 'SCSS', value: 'scss' }
                                ] }
                                onChange={ ( language ) => { props.setAttributes( {language} ) } }
                            />

                            </PanelRow>
                        </PanelBody>
                    </InspectorControls>
                    <div className={ `gutenberg-code-highlighter ${props.attributes.language} ` }>
                        <BlockEdit {...props} />
                    </div>
                </Fragment>
            );

        }

    });

    return withInspectorControls(BlockEdit);

}

Original: https://github.com/derweili/gutenberg-code-highlighter/blob/master/filters/code-block/index.js

Die Callback Funktion des Filters nimmt hier nur einen Paramter engegen, den BlockEdit Parameter. Bei diesem handelt es sich um den Edit Component des ursprünglichen Blocks.

Wir können den Block Edit Component nicht direkt verändern. Stattdessen umschließen wir diesen mit einem Fragment. In diesem Fragment erstellen wir Inspector Controls die in der Block Sidebar des Blocks angezeigt werden.

Wir erstellen also einen High Order Component, in dem wir den den Block Edit Component mit einem ein <Fragment> umschließen.
Achtung: wir dürfen nicht vergessen, die props an den Component weiterzugeben.
In das Fragment Element können wir außerdem InpectorControl einfügen und so die Block Sidebar des Code Blocks um z.B. Radio Controls erweitern.

Diese Radio Controls bilden das UI für die zuvor registrierten Blockattribute.

Über props.attributes können wir auf die Blockattribute zugreifen und diese auch über props.setAttribute() verändern.

Fazit

Es kann Sinnvoll sein neue Blöcke zu erstellen, wir sollten aber immer überlegen, ob es nicht nachhaltiger ist, bestehende Blöcke zu erweitern. Gutenberg bietet uns dafür einige Möglichkeiten die wir uns auf jeden Fall anschauen sollten.