In diesem Artikel werden wir einen eigenen WordPress Block entwickeln. Wir starten komplett bei null und verzichten bewusst auf Drittanbieter-Plugins, wie z.B. Advanced Custom Fields, um langfristig die volle Kontrolle zu haben.
Das bedeutet auf den ersten Blick mehr Arbeit, sichert uns jedoch nachhaltig eine gewisse Unabhängigkeit, die ich besonders bei Kundenprojekten anstrebe.
Robert Rosanke
Webentwickler
Inhaltsverzeichnis
Diesen Artikel in sozialen Netzwerken teilen:
Zielstellung in diesem Artikel
Ziel dieses Tutorials ist ein eigener Block, mit dem der Nutzer eine auffällige Infobox ohne HTML und CSS-Kenntnisse erstellen kann.
Folgende Funktionen soll der Block bieten:
- Eingabefeld für eine Überschrift, z.B. Anmerkung der Redaktion
- Container für den Inhaltsbereich, in dem der Nutzer jeden beliebigen Block verwenden kann
- Dropdown in der Sidebar mit drei Stilrichtungen, z.B. Anmerkung, Tipp, Warnung
- Einheitliche Darstellung im Backend und Frontend
Das könnte dann am Ende wie folgt aussehen:
Entwicklungsumgebung für Gutenberg einrichten
Die Einrichtung einer Entwicklungsumgebung ist nicht zwingend für jedes Vorhaben notwendig.
Der große Vorteil einer gleichbleibenden Entwicklungsumgebung: Sie bringt eine gewisse Konstanz in die Arbeitsabläufe, sodass wir effizienter arbeiten können (und werden).
Um die Umgebung für unseren ersten WordPress Block einzurichten, bin ich Florian Brinkmanns Anleitung zur Webpack-Einrichtung für die Gutenberg-Entwicklung Schritt für Schritt durchgegangen.
Diese Anleitung verzichtet auf den Einsatz von weiteren Plugins und ist ohne großes Drumherum auf den Punkt gebracht
Drei Tipps für das Tutorial von Florian:
- Geduldig sein: Besonders die Installation von node.js kann eine Weile dauern. Der Rest geht innerhalb weniger Minuten.
- Erstelle ein eigenes Plugin für all deine Blöcke, um das Theme in Zukunft einfach wechseln und die Blöcke problemlos in anderen Projekten nutzen zu können.
- Tipp für den Abschnitt „package.json erstellen und Abhängigkeiten installieren“: Pfad des neuen Plugins in der Kommandozeile öffnen geht bei Windows mit
Shift + Rechtsklick
auf den Ordner und Eingabeaufforderung hier öffnen. Der Pfad ist dann direkt anvisiert. - Verwende einen Code Editor, um die wichtigen Dateien des Projekts auf einen Blick zu haben und schnell zwischen den Dokumenten wechseln zu können. Ich nutze den kostenfreien Editor Atom.
Ebenfalls lesenswert in diesem Zusammenhang ist Thomas Weichselbaumers Anleitung zur Erstellung einer Entwicklungsumgebung mit create-guten-block.
Thomas hat mit create-guten-block eine Lösung gefunden, mit der er schnell und unkompliziert eine funktionsfähige Entwicklungsumgebung aufbauen kann.
Während der node.js Installation findest du mit Sicherheit ein paar Minuten, um mal reinzuschauen.
Sobald du die Entwicklungsumgebung eingerichtet hast, legen wir mit der Erstellung des eigenen WordPress Blocks innerhalb eines eigenen Plugins los.
Main Plugin File erstellen und Block registrieren
Sobald die Entwicklungsumbeung nach Florians Artikel aufgebaut ist, geht es mit der eigentlichen Plugin- und Block-Erstellung los.
Falls noch nicht geschehen, führen wir npm run start
in der Kommandozeile aus, damit die zukünftigen Äderungen in den .scss
-Dateien zwischen Backend und Frontend automatisch aktualisiert und übernommen werden.
Main Plugin File erstellen
Als erstes geben wir unserem Plugin die entsprechenden Header Informationen mit auf den Weg, um beispielsweise einen eigenständigen Namen inklusive aussagekräftiger Beschreibung für das Plugin-Verzeichnis festzulegen.
Falls das dein erstes Plugin ist:
Wir befinden uns jetzt auf Ebene der package.json
und in der Datei [dein-plugin-name].php
.
Meine Datei heißt wf-gutenberg-blocks.php
.
<?php
/**
*
* Plugin Name: wf info block
* Description: Ein eigener WordPress Block für Gutenberg.
* Version: Testversion
* Author: Robert Rosanke
* Author URI: https://webfluence.de/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* Text Domain: wf-block
* Domain Path: /languages
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
Weitere Informationen zum Plugin Header auf developer.wordpress.org
Styles mit register_block_type() angeben
Damit die CSS-Dateien unseres Blocks in Backend und Frontend geladen werden, registrieren wir die Styles und übergeben sie an die Funktion register_block_type()
.
Wir befinden uns noch immer im Main Plugin File und schreiben den folgenden PHP-Code direkt unter den Plugin Header.
/**
* Register block script and backend stylesheet
*/
wp_register_script(
'wf-gutenberg-blocks-editor-script',
plugins_url( 'assets/js/editor.blocks.js', __FILE__ ),
[ 'wp-blocks', 'wp-element', 'wp-edit-post', 'lodash' ]
);
wp_register_style(
'wf-gutenberg-blocks-editor-style',
plugins_url( 'assets/css/editor.blocks.css', __FILE__ )
);
/**
* Register block styles for frontend
*/
wp_register_style(
'wf-gutenberg-blocks-frontend-style',
plugins_url( 'assets/css/frontend.blocks.css', __FILE__ )
);
/**
* Enqeue scripts and styles for info-box block
*/
register_block_type(
'webfluence-block/info-box', array(
'style' => 'wf-gutenberg-blocks-frontend-style',
'editor_script' => 'wf-gutenberg-blocks-editor-script',
'editor_style' => 'wf-gutenberg-blocks-editor-style',
)
);
Block in der index.js mit registerBlockType() registrieren
Um nun einen kleinen Platzhalter-Block zu erstellen gehen wir in das Verzeichnis blocks
und öffnen die darin enthaltene index.js
.
In dieser Datei findet die ganze Magie statt.
Mit der index.js
können wir:
- Neue Blöcke registrieren
- Bestehende Core– und Custom-Blöcke modifizieren
- Bestehende Blöcke von der Block-Auswahl verstecken oder komplett „unregistern“ (Wäre deaktivieren ein passendes deutsches Wort für „unregister“?! Ich weiß es nicht..)
- Block-Kategorien bearbeiten
Für einige Modifikationen gibt es eine kleine aber offizielle Übersicht über die Block-Filter mit Code-Beispielen.
/**
* WordPress dependencies
*/
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
/**
* Register block
*/
registerBlockType( 'webfluence-block/info-box',
{
title: __( 'Info Box', 'wf-block' ),
category: 'layout',
edit() {
return (
<div>Das wird im Editor angezeigt</div>
);
},
save() {
return (
<div>Das wird im Frontend angezeigt</div>
);
},
}
);
Kurze Erklärung des Codes:
Mit const
importieren wir zu Beginn und im weiteren Verlauf der Block-Erstellung Komponenten, die wir für unseren Block brauchen.
i18n
samt __
werden dir von der Theme- und Plugin-Übersetzung via PHP mit Sicherheit schon bekannt sein.
Mehr dazu: WordPress übersetzen
registerBlockType()
beinhaltet den Namen, in unserem Fall webfluence-block/info-box
, und die weiteren Block-Settings in Form von Properties.
Die wichtigsten Properties, also die, die den Block zum laufen bringen, sind folgende:
title
legt fest, welchen Namen der Block in der Block-Auswahl erhältcategory
legt fest, in welcher Kategorie der Block-Auswahl der Block untergebracht wirdedit
ist eine Funktion, die angibt, wie der Block im Gutenberg-Editor dargestellt, wirdsave
ist eine Funktion, die angibt, wie der Block im Frontend dargestellt wird
Sobald der Block interaktiv und dynamisch wird, werden wir zudem eigene Variablen mit dem attributes
-Objekt festlegen.
Dazu kommen wir später im Artikel.
Tipp
Die edit
– und save
-Funktion beinhalten hauptsächlich das Markup und die Platzhalter für dynamische Eingaben. Die optische Darstellung wird weiterhin hauptsächlich per CSS festgelegt.
Plugin aktivieren und kurze Funktionskontrolle
Nun wechseln wir kurz ins WordPress Backend, aktivieren das Plugin und schauen, ob der Block-Platzhalter im Editor erscheint.
Statischen Basis-Block erstellen (das Grundgerüst)
Nun geht es ans eingemachte.
Der Block ist im System angekommen und es ist an der Zeit das Grundgerüst aufzubauen, damit sich der Block sowohl im Editor als auch im Frontend vom normalen Absatz-Block unterscheidet.
Wir werden jetzt das Markup festlegen und einfache Styles zuweisen, bevor es an die Integration von Eingabefeldern für den Nutzer geht.
Frontend Markup festlegen
Wichtig: Für die Gutenberg-Entwicklung schreiben wir in JSX.
JSX bringt teilweise eine eigene Syntax mit, die sich von klassischem HTML oder der Plugin-Entwicklung mit PHP abhebt.
Dadurch wird beispielsweise für das HTML-Attribut class
der Bezeichner className
verwendet und aus tabindex
wird tabIndex
, wie in der JSX-Einleitung nachzulesen ist.
save() {
return (
<div className="wf-info-block-wrapper">
<div className="wf-info-block-header">
<i className="far fa-lightbulb" aria-hidden="true"></i>
Kopfzeilen-Text
</div>
<p className="wf-info-block-content">
Content
</p>
</div>
);
},
Tipp
Damit Markup-Änderungen wirksam werden, muss der Block im Backend nach den Änderungen noch einmal neu zur Seite hinzugefügt werden. Andererseits bleibt einfach der alte Block, also unser Platzhalter-Block ohne das neue Markup, zu sehen.
Schauen wir einmal, was im Frontend zu sehen ist.
Beim genaueren Hinschauen fällt auf, dass WordPress automatisch eine weitere CSS-Klasse in das erste div
eingestzt hat. Diese besteht aus dem Prefix wp-blocks
und der Bezeichnung, mit der die Block Styles zu Beginn registriert wurden.
In meinem kleinen Test wurde auch das Individuelles CSS bereits automatisch an den Wrapper-Block übergeben, das heiß: soweit klappt alles.
Backend Markup festlegen
Da wir ein einheitliches Erscheinungsbild anstreben, passen wir nun das Backend-Markup an.
Dafür können wir den return
-Teil des Frontend Markups, bis auf eine kleine Anpassung, einfach übernehmen.
edit( props ) {
const { className } = props;
return (
<div className={ className + " wf-info-block-wrapper" }>
<div className="wf-info-block-header">
<i className="far fa-lightbulb" aria-hidden="true"></i>
Kopfzeilen-Text
</div>
<p className="wf-info-block-content">
Content
</p>
</div>
);
},
Die Klasse wp-block-webfluence-block-info-block
, die automatisch zum ersten div des Frontend Markups hinzugefügt wird, müssen wir nun manuell in das Backend Markup integrieren, um die Einheitlichkeit zu erreichen.
Dafür wird lediglich das erste div
ein wenig angepasst.
Im ersten Teil der Klassenzuweisung wird mit className={ className
die automatisch generierte Klasse wp-block-webfluence-block-info-block
übergeben.
Anschließend fügen wir mit + " wf-info-block-wrapper" }
unsere eigene Wrapper-Klasse hinzu.
Die geschweiften Klammern werden in JSX vereinfacht gesagt genutzt, um inline JavaScript auszuführen. Und um unsere CSS-Klasse (ein string) abzugrenzen, werden die hochgestellten Anführungszeichen genutzt.
Ich gehe davon aus, dass diese Vorgehensweise mit dem + und einem „string“ nicht best practise sind, um in JSX mehrere CSS-Klassen zuzuweisen. Doch für den Anfang funktioniert die Schreibweise und das ist das wichtigste für den ersten Block.
Die Styles laden
Wenn du das Setup nach der Anleitung von Florian Brinkmann aufgebaut hast, dann steht in der Datei editor.scss
bereits @import ‚./frontend‘;
.
Dadurch werden die Styles aus dem Frontend-Dokument automatisch ins Backend-Dokument übernommen, sodass das Design nur einmal erstellt werden muss und auf Backend und Frontend angewendet wird.
Meine frontend.scss
sieht nun so aus:
.wf-info-block-wrapper {
background-color: #f4f4f4;
}
.wf-info-block-header {
background-color: #e6e6e6;
font-weight: 600;
padding: 5px;
}
.wf-info-block-header i {
color: yellow;
margin-right: 8px;
}
.wf-info-block-content {
margin: 0;
padding: 10px 5px;
}
Nachdem alles gespeichert ist, sind die Styles soweit auch übernommen.
Lediglich FontAwesome muss per Plugin Main File noch in die Website integriert werden. Sowohl Frontend als auch Backend.
Tipp
Da ich hier ‚nur‘ eine lokale Testumgebung auf dem eigenen PC habe, habe ich an dieser Stelle den schnelleren Weg gewählt und ziehe FontAwesome von externen Servern.
Viele Menschen empfehlen FontAwesome, jQuery und weitere bekannte Frameworks seit der Datenschutz-Grundverordnung lokal zu hosten und einzubinden. Bei Plugins für Live-Seiten strebe ich an, diese Empfehlung umzusetzen.
/**
* Enqueue FontAwesome for backend.
*/
add_action( 'admin_enqueue_scripts', function() {
wp_enqueue_style('admin-styles', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css');
} );
/**
* Enqueue FontAwesome for frontend.
*/
add_action( 'wp_enqueue_scripts', function() {
wp_register_style( 'wf-fontawesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css', $deps, $ver = null, $media = 'all' );
wp_enqueue_style('wf-fontawesome');
} );
Kurzer Check – Sind die Icons angekommen?
Den WordPress Block mit Komponenten erweitern
Damit der Block nun auch verwendet werden kann, fehlen lediglich die Eingabefelder, mit denen der Nutzer zukünftig eine Überschrift sowie den Inhalt für die Infobox festlegen kann.
Für den angedachten Verwendungszweck sind 3 Funktionen notwendig.
- Text soll in die Kopfzeile eingegeben werden können
- Der Inhalt soll aus weiteren Blöcken bestehen. Der Nutzer soll selbständig entscheiden, ob er Fotos, Embeds, Listen etc. oder auch mehrere verschiedene Blöcke in den Inhaltsbereich der Info-Box integriert.
- Stil der Box soll in der Sidebar ausgewählt werden können
- Tipp = Grüne Lampe als Icon
- Achtung = Rotes Schild als Icon
- Anmerkung = Blaues i-Symbol
Eingabefeld erstellen mit RichText
Schritt 1: RichText-Komponente integrieren
Um editierbare Eingabefelder für unseren Block zu ermöglichen brauchen wir eine RichText-Komponente.
Füge dazu const { RichText } = wp.editor;
an den Anfang der index.js
hinzu.
Schritt 2: Eingabefeld erstellen
Derzeit sieht unser Platzhalter für das Kopfzeilen-Eingabefeld in der edit
-Funktion wie folgt aus:
<div className="wf-info-block-header">
<i className="far fa-lightbulb" aria-hidden="true"></i>
Kopfzeilen-Text
</div>
Um den Platzhalter gegen ein Eingabefeld auszutauschen, nutzen wir die eben integrierte RichText-Komponente.
Im folgenden Beispiel erstellen wir ein Eingabefeld, dass nun unseren statischen Platzhalter ersetzt.
<RichText
tagName="p"
value={ attributes.boxTitle }
className="wf-info-block-header"
onChange={ changeBoxTitle }
placeholder={ __( 'Add a title…', 'wf-block' ) }
keepPlaceholderOnFocus
/>
Das FontAwesome-Icon hat den Umstieg auf die RichText-Komponente nicht überlebt und wird später wieder hinzugefügt…
Das wichtigste erklärt:
tagName
legt fest, welchen HTML-Tag das Eingabefeld im Backend-Editor erhalten soll
value
bestimmt den Wert, sprich den Inhalt des Eingabefelds
className
legt die CSS-Klasse fest
onChange
ruft eine Funktion auf, die bei Änderungen durch den Nutzer im Backend aufgerufen wird
placeholder
stellt einen Platzhalter bereit, den der Nutzer im Backend sieht, wenn er noch kein individueller Inhalt eingefügt hat
keepPlaceholderOnFocus
legt fest, dass der Platzhalter weiterhin angezeigt werden soll, wenn der Nutzer den leeren Block fokussiert
Eine umfassende Liste mit weiteren RichText-Properties gibt es auf GitHub.
Damit das Eingabefeld funktionstüchtig wird, müssen wir die value
und onChange
Properties der RichText-Komponente nun mit Inhalten füttern.
Schritt 2.1 Attribut für die value-Property erstellen
Damit der Gutenberg-Editor den Wert des Eingabefeldes auch nach dem Abspeichern und neu laden des Beitrags wiederfindet, durchsucht er die Code-Ansicht und baut sich daraus die visuelle Ansicht, die der Anwender genießen darf.
Mit unserer Angabe value={ attributes.boxTitle }
sucht der Editor nun nach dem Attribut boxTitle
.
Damit die Suche erfolgreich endet, fügen wir folgenden Code hinter den Basis Infos zum Block, also hinter title
, category
, etc., hinzu und erstellen das Attribut:
attributes: {
boxTitle: {
type: 'string',
source: 'html',
selector: '.wf-info-block-header',
}
},
Das nun erstellte boxTitle
-Attribut sagt dem Editor, wonach er suchen muss, um das Eingabefeld zu befüllen.
Der Editor durchsucht die Code-Ansicht nach Elementen mit der Klasse .wf-info-block-header
und hat durch source: 'html',
Zugriff auf den gesamten HTML-Inhalt dieser Elemente.
Somit können wir damit den bestehenden Inhalt aus dem Eingabefeld auslesen.
/* Ein Beispiel zur Veranschaulichung */
<p class="wf-info-block-header"><strong>Geänderte Öffnungszeiten<strong> im Herbst</p>
/* Wert von boxTitle: <strong>Geänderte Öffnungszeiten<strong> im Herbst */
Hätten wir stattdessen source: 'text',
gewählt, dann würde lediglich der Text ohne die <strong>
-Tags übermittelt.
Weitere Informationen zu Attributen
Schritt 2.2 Funktion für die onChange-Property erstellen
Damit der Inhalt des Eingabefelds mit dem eben festgelegten Element synchronisiert wird, sobald der Nutzer dort etwas anderes eingibt, müssen wir die Funktion erstellen, die wir an die onChange
-Property übermittelt haben.
Hier noch einmal die entsprechende Zeile:
onChange={ changeBoxTitle }
Sobald der Nutzer den Wert des Eingabefelds ändert, wird die Funktion changeBoxTitle()
aufgerufen.
In unserem Beispiel soll diese Funktion den neu eingegeben Wert dem boxTitle
zuweisen, weil dieser Zugriff auf unser Element mit der CSS-Klasse .wf-info-block-header
hat.
Und das Element mit dieser CSS-Klasse ist schließlich das, worin sich die Überschrift unserer Infobox befindet.
Deshalb fügen wir folgenden Schnipsel vor das return
-Statement innerhalb der edit
-Funktion ein.
function changeBoxTitle( newBoxTitle ) {
setAttributes( { boxTitle: newBoxTitle } );
}
Die onChange
-Property übermittelt den neuen Eingabefeld-Wert mit der Variable newBoxTitle
an die Funktion changeBoxTitle()
.
Das einzige was die Funktion tut ist es das Attribut boxTitle
zu nehmen und diesem den neuen Wert zuzuschreiben.
Tipp
Die Bezeichnung newBoxTitle
ist an dieser Stelle frei gewählt und muss nirgendwo außerhalb der Funktion deklariert werden. Du kannst natürlich einen anderen Bezeichner wählen, der besser zu deinem Vorhaben passt.
Schritt 2.3 Properties der edit-Funktion aktualisieren
Um das Attribut boxTitle
an die edit
-Funktion zu übergeben, tauschen wir die bestehende Zeile Code
const { className } = props;
gegen folgenden Absatz aus:
const {
attributes,
className,
setAttributes,
} = props;
Die edit
-Funktion sieht nun wie folgt aus:
edit( props ) {
const {
attributes,
className,
setAttributes,
} = props;
function changeBoxTitle( newBoxTitle ) {
setAttributes( { boxTitle: newBoxTitle } );
}
return (
<div className={ className }>
<div className="wf-info-block-wrapper">
<RichText
tagName="p"
value={ attributes.boxTitle }
className="wf-info-block-header"
onChange={ changeBoxTitle }
placeholder={ __( 'Add a title…', 'wf-block' ) }
keepPlaceholderOnFocus
/>
<p className="wf-info-block-content">
Content
</p>
</div>
</div>
);
},
Kurzer Zwischenstand
So sieht unser Block im Backend aus
Schritt 3: Eingabefeld-Wert mit RichText.Content an den Post Content übermitteln
Jetzt wo der Gutenberg-Editor im Backend den Post Content nach unserem Wert für das Eingabefeld durchsuchen und diesen unserem Block zuordnen kann, ist es an der Zeit die Frontend Ausgabe anzupassen.
Dafür ersetzen wir in der save
-Funktion die statische Platzhalter Überschrift
<div className="wf-info-block-header">
<i className="far fa-lightbulb" aria-hidden="true"></i>
Kopfzeilen-Text
</div>
mit dem folgendem Part:
<RichText.Content
tagName="p"
className="wf-info-block-header"
value={ boxTitle }
/>
Mit RichText.Content
und der obigen Konfiguration erhalten wir den Eingabefeld-Wert über die Property value
und setzen ihn das eigens kreierte p
-Element mit der CSS-Klasse wf-info-block-header
.
Somit haben wir den Wert, der bis dato lediglich im Gutenberg-Editor gespeichert war, aufgegriffen und in der Code-Ansicht abgelegt.
Ebenso übermittelten wir der save-Funktion die Attribute, um RichText.Content
den Zugriff auf den boxTitle
zu ermöglichen.
save( { attributes } ) {
const {
boxTitle,
} = attributes;
return (
....
Die save
-Funktion sieht nun wie folgt aus:
save( { attributes } ) {
const {
boxTitle,
} = attributes;
return (
<div className="wf-info-block-wrapper">
<RichText.Content
tagName="p"
className="wf-info-block-header"
value={ boxTitle }
/>
<p className="wf-info-block-content">
Content
</p>
</div>
Dank RichText
und RichText.Content
kann der Titel manuell vom Nutzer editiert und ausgegeben werden.
Das FontAwesome-Icon habe ich mit dem einfügen der RichText
-Komponente entfernt, weil es später als Pseudo-Element mit einer CSS-Klasse hinzugefügt werden soll.
Dadurch wird die Infobox flexibler und fortgeschrittene User mit CSS-Kenntnissen können die Styles der Box ändern und bei Bedarf einen individuellen, weiteren Boxen-Stil erstellen.
Blöcke innerhalb eines Blocks erlauben mit InnerBlocks
So.
Das Eingabefeld für den Header ist erstellt und vollständig funktionsfähig.
Ich will uns an dieser Stelle kurz die Zielstellung zurück ins Gedächtnis rufen.
Eingabefeld für eine Überschrift, z.B. Anmerkung der Redaktion- Container für den Inhaltsbereich, in dem der Nutzer jeden beliebigen Block verwenden kann
- Dropdown in der Sidebar mit drei Stilrichtungen, z.B. Anmerkung, Tipp, Warnung
Einheitliche Darstellung im Backend und Frontend
Zwei der vier Zielstellungen sind bereits abgehakt.
Fahren wir zur Erholung kurz mit einem einfachen und entspannten Thema fort.
InnerBlocks.
Mit <InnerBlocks />
können wir dem Nutzer erlauben selbständig Blöcke innerhalb eines Containers zu verwenden.
Schritt 1: InnerBlocks-Komponente integrieren
Wir fügen InnerBlocks zu den Konstanten am Beginn der index.js
hinzu:
const { InnerBlocks } = wp.editor;
Schritt 2: Bereich für freie Block-Auswahl festlegen
An der Stelle, an der der Nutzer selbständig Blöcke hinzufügen darf, fügen wir <InnerBlocks />
ein.
Da jeder Block sein eigenes Markup mitbringt, tauschen wir den p
-tag gegen ein div
aus, sodass folgendes Ergebnis in der edit
-Funktion anstelle der Platzhalters herauskommt:
<div className="wf-info-block-content">
<InnerBlocks />
</div>
In diesem Fall soll der Nutzer frei entscheiden dürfen, welche Blöcke er in den Content-Bereich der Infobox packt.
Falls das bei dir nicht erwünscht ist, dann kannst du ein Array mit erlaubten Blöcken festlegen.
<InnerBlocks allowedBlocks={ [ 'core/heading', 'core/paragraph' ] } />
Bei wpdc gibt es eine Auflistung der Core-Block-Slugs, mit denen du schnell und einfach herausfindest, welche Bezeichnungen die Blocks intern nutzen.
Eine umfassende Liste mit weiteren InnerBlocks-Properties gibt es auf GitHub.
Schritt 3: Eingefügte Blöcke mit InnerBlocks.Content im Frontend ausgeben
Um den Content der inneren Blöcke an das Frontend zu übermitteln, fügen wir <InnerBlocks.Content />
in die save
-Funktion ein.
<div className="wf-info-block-content">
<InnerBlocks.Content />
</div>
Ergebnis: Nun kann der Nutzer weitere Blöcke im Content-Bereich der Infobox verwenden.
Die Ausgabe funktioniert soweit auch. Lediglich am CSS sollten wir vor der Integration des Blockes noch einmal schrauben.
Quelle: https://www.ibenic.com/enable-inner-blocks-gutenberg/
Sidebar Einstellungen hinzufügen mit InspectorControls
Kommen wir zur letzten, wichtigen Aufgabe.
Wir erteilen dem Block nun drei Design-Stile, die der Nutzer bequem aus einem Dropdown in den Block-Einstellungen der Sidebar auswählen kann.
Ähnlich wie Text im Paragraph-Block die Stile „klein“, „normal“ und „groß“ erhalten kann, soll unser Block folgende Stile bzw. Auswahlmöglichkeiten erhalten:
- Anmerkung
- Info
- Warnung
Jeder Stil soll dem Block dann eine CSS-Klasse hinzufügen.
Mit dieser CSS-Klasse können wir nachhaltig und ohne großen Programmieraufwand individuelle Erscheinungsbilder für die verschiedenen Stile festlegen und über das CSS-Pseudo-Element :before
ein FontAwesome-Icon hinzufügen.
Als erstes fügen wir neue Konstanten an den Anfang der index.js
ein:
const { InspectorControls } = wp.editor;
const { PanelBody } = wp.components;
Jetzt wird es ein wenig tricky.
Deshalb erstellen wir einen Platzhalter, den wir zuerst Testweise in der Sidebar positionieren.
<InspectorControls>
<PanelBody title={ __( 'Choose Style', 'wf-block' ) }>
<p>Lorem ipsum</p>
</PanelBody>
</InspectorControls>
Damit die Einstellungen in die Sidebar wandern, muss die edit
-Funktion angepasst werden.
Aus der einfachen Ausgabe des Inhalts wird nun ein Array, das neben dem bisherigen Block-Content die Sidebar-Inhalte, also das InspectorControls-Element, beinhaltet.
Hier noch einmal veranschaulicht:
vorher:
return (
//ein paar div-container und eine RichText-Komponente
);
},
jetzt:
return [ // aus normaler Klammer wird eine eckige Klammer
<InspectorControls>
<PanelBody title={__("Choose Style", "wf-block")}>
<p>Lorem ipsum</p>
</PanelBody>
</InspectorControls>, // hier ist ein Komma dazugekommen
// ein paar div-container und eine RichText-Komponente...
]; // aus normaler Klammer wird eine eckige Klammer
},
Nach dem Abspeichern sind die Überschrift sowie der Platzhalter erfolgreich in der Sidebar angekommen.
Nun muss das Ganze noch funktional werden:
- Dropdown mit verschiedenen Stilen bereistellen
- Jeder Stil fügt der Infobox eine individuelle CSS-Klasse hinzu
Dropdown einfügen mit SelectControl
Schritt 1: SelectControl-Komponente importieren
Wir begeben uns wieder an den Anfang der index.js
und importieren die SelectControl-Komponente.
const { SelectControl } = wp.components;
Schritt 2: Attribut mit Standardwert hinzufügen
Wir fügen unseren attributes
ein weiteres Mitglied hinzu.
selectedStyle: {
type: 'string',
default: 'info',
},
Das neue Attribut selectedStyle
beinhaltet den Standardwert für das Auswahlfeld.
Da ich schätze, dass der Info-Kasten der meist genutzte Stil sein wird, habe ich mit default: 'info',
einen entsprechenden Standardwert festgelegt.
Schritt 3: Dropdown integrieren und Werte festlegen
In der edit
-Funktion schmeiße ich den „Lorem ipsum“ Platzhalter raus und setze dafür das Dropdown-Menü ein.
<SelectControl
label={__("Choose info box style", "wf-block")}
value={props.attributes.selectedStyle}
onChange={(selectedStyle) => {
props.setAttributes({ selectedStyle });
}}
options={[
{ value: "annotation", label: "Anmerkung" },
{ value: "info", label: "Info" },
{ value: "warning", label: "Warnung" }
]}
/>
Der Code erklärt:
label
lässt uns den Bezeichner für das Dropdown festlegen.
value
ruft das Attribut, dem der Wert zugeordnet werden soll. Ein einfacher 'string'
sollte auch möglich sein.
onChange
lässt uns festlegen, was passieren soll, wenn der Nutzer eine Option des Dropdowns wählt. Hier hätten wir natürlich auch eine Funktion erstellen und aufrufen können, wie bei dem RichText-Element für das individuelle Eingabefeld.
options
lässt uns die Auswahlmöglichkeiten festlegen. value
ist der Wert, mit dem das System arbeitet und label
die Beschriftung, die der Nutzer sieht.
Schritt 4: Dropdown-Werte auf die optische Darstellung anwenden
Je nachdem, welche Option der Nutzer ausgewählt hat, hat das Attribut selectedStyle
einen der folgenden Werte:
- annotation
- info
- warning
Das Ziel ist es jetzt diesen Wert in der save
-Funktion mittels CSS-Klasse an die Infobox zu übermitteln.
Hier noch einmal der aktuelle Stand der save
-Funktion:
save({ attributes }) {
const { title } = attributes;
return (
<div className="wf-info-block-wrapper">
<RichText.Content
tagName="p"
className="wf-info-block-header"
value={title}
/>
<div className="wf-info-block-content">
<InnerBlocks.Content />
</div>
</div>
);
},
Mit einer dynamischen CSS-Klasse ala wf-info-box-style-[hier den ausgewählten Wert einsetzen]
, die an den ersten, äußeren div
-Container übermittelt wird, hätten wir eine ziemlich effiziente Lösung für das Styling gefunden, weil Icon zukünftig mittels CSS geändert werden können anstatt jeden Block einzeln in der index.js
zu bearbeiten und Invalidation Errors zu riskieren.
Der Wrapper-Container, der im Frontend am Ende ausgegeben werden soll, ist bis jetzt <div className= "wf-info-block-wrapper">
.
In der edit
-Funktion machen wir aus dieser Zeile nun folgende:
<div className={ "wf-info-block-wrapper wf-info-block-style-" + attributes.selectedStyle }>
Diese Zeile beinhaltet die Wrapper-Klasse wf-info-block-wrapper
und die Klasse wf-info-block-style-
, die automatisch um den Wert der in der Sidebar ausgewählten Dropdown-Option erweitert wird.
Entsprechend der drei möglichen Auswahlpunkte entstehen somit folgende Klassen, die später per CSS festgelegt werden müssen:
wf-info-block-style-annotation
wf-info-block-style-info
wf-info-block-style-warning
Damit der Dropdown-Wert auch an die save
-Funktion übermittelt und in den Post Content übergeben wird, fügen wir am Anfang der save
-Funktion das Attribut selectedStyle
hinzu und integrieren das Attribut entsprechend in den äußeren div
-Container des Markups.
save( { attributes } ) {
const {
title,
selectedStyle,
} = attributes;
return (
<div className={ "wf-info-block-wrapper wf-info-block-style-" + selectedStyle }>
…..
Ein kleiner Blick in die Chrome DevTools verrät, dass das Markup entsprechend der gewählten Stilrichtungen ausgegeben wird.
Im Backend klappt es ebenso problemlos.
Anwendungsbeispiele für CheckBoxen, Textfelder und Weiteres mit InspectorControls gibt es auf GitHub.
Außerdem gibt es auf GitHub eine Liste mit allen Komponenten, falls du weitere Funktionen, wie ein festes Media-Upload-Feld, hinzufügen willst
Schritt 5: Finales Styling mit CSS
Mit nur wenigen Zeilen CSS sind die Blöcke gestaltet und werden dank dem smarten Setup automatisch auch im Backend entsprechend dargestellt.
Toolbar-Einstellungen verfeinern
Jetzt wo der Block an sich fertig ist, habe ich spontan festgestellt, dass eine weite Breite bei einer Infobox durchaus sinnvoll sein könnte.
Deshalb fügen wir nach dem attributes
-array folgendes in die index.js
:
supports: {
align: [ 'wide' ],
},
Nun kann der Nutzer die Option ‚weite Breite‘ wählen, wie es beim Bild-Block standardmäßig möglich ist.
Für weitere Einstellungen, wie zum Beispiel die Aktivierung des HTML-Anker Felds, das es sonst nur bei Überschriften gibt, lohnt ein Blick in das Block Editor Handbook.
Finale Optimierungen
Zu guter letzt räumen wir den Code noch ein bisschen auf.
Konstanten zu arrays machen
Aus:
/**
* WordPress dependencies
*/
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { RichText } = wp.editor;
const { InnerBlocks } = wp.editor;
const { InspectorControls } = wp.editor;
const { PanelBody } = wp.components;
const { SelectControl } = wp.components;
Wird:
/**
* WordPress dependencies
*/
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { InspectorControls,
InnerBlocks,
RichText
} = wp.editor;
const { PanelBody,
SelectControl
} = wp.components;
Weitere Informationen für den Block bereitstellen
Zum aktuellen Zeitpunkt hat unser Block lediglich eine Bezeichnung und ist einer Kategorie zugeordnet.
Es wird daher Zeit ein eigenes Icon, eine passende Beschreibung und Suchbegriffe für die Block-Auswahl festzulegen festzulegen.
/**
* Register block
*/
registerBlockType("webfluence-block/info-box", {
title: __("Info Box", "wf-block"),
description: __(
"Highlight important information in a custom info box.",
"wf-block"
),
// Core categories: common, embed, formatting, layout, widgets
category: "layout",
// Dashicons - https://developer.wordpress.org/resource/dashicons/#wordpress
icon: "warning",
keywords: [
__("annotation", "wf-block"),
__("information", "wf-block"),
__("warning", "wf-block"),
__("box", "wf-block")
],
// attributes, etc. ...
});
Diesen Artikel in sozialen Netzwerken teilen: