Block Entwicklung
![]() | Diese Seite ist in Bearbeitung. In naher Zukunft werden die fehlenden Informationen ergänzt sein. Bitte besuchen Sie mich hier zu einem späteren Zeitpunkt wieder. |
Hier sammle ich ein paar Infos zur Blockentwicklung für das Projekt Gutenberg in WordPress. Da Blöcke immer in einem PlugIn untergebracht werden müssen, ist eventuell auch der Artikel PlugIn-Entwicklung für dich interessant.
Als Leitfaden dient auch gerne das offizielle Block-Editor Handbuch von WordPress.
Die Zielstellung
Hier werde ich einen WordPress-Block entwickeln, der eine Infobox erstellt.
- Diese Infobox erhält eine Texteingabe für die Überschriftenleiste.
- Der Content der Infobox soll durch die Verwendung von den in WP enthaltenen Standard-Blöcken erstellt werden können.
- Außerdem kann der Redakteur in der Block-Einstellung ein Styling auswählen (Anmerkung, Info und Warnung).
- Der Block wird in einem eigenen Plugin integriert bzw. entwickelt.
Voraussetzungen
Ich gehe davon aus, dass ihr
- eine lokale WordPress-Installation laufen und
- Node sowie NPM (kommt in der Regel mit der Node-Installation mit) installiert habt.
Einen Block erstellen
Hier wählen wir den einfachen und schnellen Weg und setzen Create Guten Block von Ahmad Awais ein. Dabei handelt es sich um ein Zero Configuration Dev-Toolkit für WordPress Gutenberg Blocks, sodass wir React, Webpack und Babel nicht selbst konfigurieren müssen.
Die Installation erfolgt über die Kommandozeile. Begebe dich dazu als Erstes in das Plugin-Verzeichnis deiner lokalen WordPress Website.
cd wp-content/plugins
Anschließend kannst du dein Block Plugin mit dem Befehl npx create-guten-block erstellen. Dem Kommando wird außerdem der Name für das WordPress Plugin übergeben. Du kannst einen beliebigen Namen für dein PlugIn wählen. Hier verwenden wir hb-blocks.
npx create-guten-block hb-blocks
Das Tool legt für uns den Plugin-Ordner an und installiert alle benötigten Node Module. Die Installation kann allerdings ein paar Minuten in Anspruch nehmen.
Das Toolkit hat das Plugin erstellt, welches bereits einen Dummy-Block enthält..
Block Plugin in WordPress aktivieren
Nach Abschluss der Installation kannst du das Plugin in deinem WordPress Backend unter "Plugins" aktivieren:
Dummy-Block in Beitrag einfügen
Das Toolkit erstellt einen Dummy-Block. Im Gutenberg Editor kannst du nach CGB Block suchen, um diesen einzufügen. Der Block zeigt nur etwas Text, ohne Eingabefelder oder Optionen. Wir werden später den Namen ändern und den Block editierbar machen.
Struktur des WordPress Block Plugins
Unser PlugIn trägt den Namen hb-blocks. Im Verzeichnis /wp-content/plugins wird also das Verzeichnis hb-blocks (PlugIn-Hauptverzeichnis) erstellt. Im Unterverzeichnis /src wird das Verzeichnis infobox erstellt. Darin befinden sich die eigentlichen Daten für die Blockentwicklung.
PHP Dateien
Im PlugIn-Hauptverzeichnis werden in der plugin.php die Blöcke initialisiert, bzw auf die init.php im Verzeichnis /src weitergeleitet:
<?php
/**
* Plugin Name: HB Blocks
* Plugin URI: https://becker-heiko.de/
* Description: HB Blocks - A collection of blocks for the Gutenberg editor.
* Author: Heiko Becker
* Author URI: https://becker-heiko.de/
* Version: 0.1.0
* License: GPL2+
* License URI: https://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: hb-blocks
* Domain Path: /languages
*
* @package CGB
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Block Initializer.
*/
require_once plugin_dir_path( __FILE__ ) . 'src/init.php';
In der /src/init.php werden die Styles und Scripte für die Blöcke initialisiert. Aus Gründen der Übersichtlichkeit habe ich die meisten Kommentare entfernt:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function hb_blocks_cgb_block_assets() {
// Register block styles for both frontend + backend.
wp_register_style(
'hb_blocks-cgb-style-css',
plugins_url( 'dist/blocks.style.build.css', dirname( __FILE__ ) ),
is_admin() ? array( 'wp-editor' ) : null, null
);
// Register block editor script for backend.
wp_register_script(
'hb_blocks-cgb-block-js',
plugins_url( '/dist/blocks.build.js', dirname( __FILE__ ) ),
array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ),
null,
true
);
// Register block editor styles for backend.
wp_register_style(
'hb_blocks-cgb-block-editor-css',
plugins_url( 'dist/blocks.editor.build.css', dirname( __FILE__ ) ),
array( 'wp-edit-blocks' ),
null
);
// WP Localized globals. Use dynamic PHP stuff in JavaScript via `cgbGlobal` object.
wp_localize_script(
'hb_blocks-cgb-block-js',
'cgbGlobal',
[
'pluginDirPath' => plugin_dir_path( __DIR__ ),
'pluginDirUrl' => plugin_dir_url( __DIR__ ),
]
);
// Register Gutenberg block on server-side.
register_block_type(
'cgb/block-hb-blocks', array(
'style' => 'hb_blocks-cgb-style-css',
'editor_script' => 'hb_blocks-cgb-block-js',
'editor_style' => 'hb_blocks-cgb-block-editor-css',
)
);
}
add_action( 'init', 'hb_blocks_cgb_block_assets' );
Ordner dist/
In diesem Verzeichnis finden sich die JavaScript- und css-Dateien, die während des Build-Vorganges für die produktive Verwendung des Plugins erstellt werden.
Ordner src/
In diesem Verzeichnis finden sich die für die Blockentwicklung zuständigen Dateien.
Das Verzeichnis /block beinhaltet den Dummy-Block. Dieses Verzeichnis nutze ich gerne als Basis für meine eigenen Blöcke. Darum lösche ich es erst, wenn das PlugIn veröffentlicht werden soll.
Im Verzeichnis /infobox entwickeln wir den Infobox-Block aus dieser Infosammlung.
Block Development mit create-guten-block
Die /src/infobox/block.js registriert den Block und wird so aussehen:
/**
* WordPress dependencies
*/
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
/**
* Internal dependencies
*/
import './style.scss';
import Edit from './edit';
import save from './save';
/**
* Register block
*/
registerBlockType( 'hb-blocks/infobox',
{
title: __( 'HB Infobox', 'hb-blocks' ),
icon: 'edit-page',
description: 'Create your own infoblock.',
category: 'widgets',
attributes: {
title: {
type: 'string',
source: 'html',
selector: '.hb-infobox-header',
},
selectedStyle: {
type: 'string',
default: 'info',
},
},
supports: {
align: [ 'wide' ],
},
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
}
);
Frontend Markup festlegen
Die /src/infobox/save.js wird so aussehen:
/**
* WordPress dependencies
*/
const { RichText } = wp.editor;
const { InnerBlocks } = wp.editor;
/**
* The save function defines the way in which the different attributes should
* be combined into the final markup, which is then serialized by the block
* editor into `post_content`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
*
* @return {WPElement} Element to render.
*/
export default function save( { attributes } ) {
const {
title,
selectedStyle,
} = attributes;
return (
<div className={ 'hb-infobox-wrapper hb-infobox-block-style-' + selectedStyle }>
<RichText.Content
tagName="p"
className={ 'hb-infobox-header-' + selectedStyle }
value={ title }
/>
<div className={ 'hb-infobox-content-' + selectedStyle }>
<InnerBlocks.Content />
</div>
</div>
);
}
Backend Markup festlegen
Die /src/infobox/edit.js wird so aussehen:
/**
* WordPress dependencies
*/
const { __ } = wp.i18n;
const { RichText } = wp.editor;
const { InnerBlocks } = wp.editor;
const { InspectorControls } = wp.editor;
const { PanelBody } = wp.components;
const { SelectControl } = wp.components;
// eslint-disable-next-line valid-jsdoc
/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
*
* @return {WPElement} Element to render.
*/
export default function Edit( props ) {
const {
attributes,
className,
setAttributes,
} = props;
function changeTitle( newTitle ) {
setAttributes( { title: newTitle } );
}
return [
// eslint-disable-next-line react/jsx-key
<InspectorControls>
<PanelBody title={ __( 'Choose Style', 'hb-blocks' ) }>
<SelectControl
label={ __( 'Choose info box style', 'hb-blocks' ) }
value={ props.attributes.selectedStyle }
onChange={ ( selectedStyle ) => {
props.setAttributes( { selectedStyle } );
} }
options={ [
{ value: 'annotation', label: 'Anmerkung' },
{ value: 'info', label: 'Info' },
{ value: 'warning', label: 'Warnung' },
] }
/>
</PanelBody>
</InspectorControls>,
// eslint-disable-next-line react/jsx-key
<div className={ 'hb-infobox-wrapper hb-infobox-style-' + attributes.selectedStyle }>
<RichText
tagName="p"
value={ attributes.title }
className={ 'hb-infobox-header-' + attributes.selectedStyle }
onChange={ changeTitle }
placeholder={ __( 'Placeholder Text', 'hb-blocks' ) }
keepPlaceholderOnFocus
/>
<div className={ 'hb-infobox-content-' + attributes.selectedStyle }>
<InnerBlocks />
</div>
</div>,
];
}
Das Styling
Die /src/infobox/style.scss beinhaltet das Styling für die Infobox (Frontend + Backend) und wird so aussehen:
.hb-infobox-wrapper {
border: 1px solid;
border-color: rgb(164, 162, 162);
border-radius: 5px;
box-shadow: 5px 10px 10px rgba(136, 136, 136, 0.22);
}
.editor-styles-wrapper p {
margin-top: 0 !important;
margin-bottom: 0 !important;
}
.hb-infobox-header-info {
background-color: blue;
font-weight: 600;
padding: 5px;
color: white;
margin: 0;
border-radius: 4px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.hb-infobox-header-annotation {
background-color: green;
font-weight: 600;
padding: 5px;
color: white;
margin: 0;
border-radius: 4px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.hb-infobox-header-warning {
background-color: red;
font-weight: 600;
padding: 5px;
color: white;
margin: 0;
border-radius: 4px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.hb-infobox-content-annotation {
background-color: rgba(172, 238, 116, 0.59);
margin: 0;
padding: 10px 5px;
}
.hb-infobox-content-warning {
background-color: rgba(255, 0, 0, 0.2);
margin: 0;
padding: 10px 5px;
}
.hb-infobox-content-info {
background-color: rgba(148, 171, 239, 0.41);
margin: 0;
padding: 10px 5px;
}
Den WordPress Block mit Komponenten erweitern
Ausgangsbasis war ja der Dummy-Block. Hier beschreibe ich nun die notwendigen Ergänzungen, wie sie in den oben aufgeführten Dateien schon zu sehen sind.
RichText-Komponente integrieren
Eingabefeld erstellen
Blöcke innerhalb eines Blocks erlauben mit InnerBlocks
Sidebar Einstellungen hinzufügen mit InspectorControls
Dropdown für die Styling-Auswahl einfügen mit SelectControl
Toolbar-Einstellungen verfeinern
Finale Optimierungen
Multilingualer Block
Anmerkungen
Absichern der php-Dateien
Um einen Zugriff von außerhalb unserer WP-Installation zu unterbinden, füge folgenden Codeschnipsel am Anfang jeder PHP-Datei ein:
<?php
// kein Plugin-Zugriff bei direktem Aufruf
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
Damit wird überprüft, ob die Variable "ABSPATH" gesetzt ist. Dies erfolgt zur Laufzeit von WP. Ist das nicht der Fall, wird die Ausführung abgebrochen.
Dashicons
https://developer.wordpress.org/resource/dashicons
In Zeile 4 findest Du ein Beispiel zur Einbindung eines WP-DashIcons.
registerBlockType( 'gutenberg-examples/example-01-basic-esnext', {
apiVersion: 2,
title: 'Example: Basic (esnext)',
icon: 'universal-access-alt',
category: 'design',
example: {},
edit() {},
save() {},
} );
Auf der oben verlinkten Übersicht wird das Icon mit dashicons-universal-access-alt angegeben. Beim Einbinden entfällt der Teil dashicons-!