22.3. Blöcke transformieren

In den letzten zwei Kapiteln haben wir uns angeschaut, wie wir Gutenberg Blöcke programmieren und Einstellungen in die Seitenleiste verlagern können. Auf dieser Seite geht es nun darum, wie sich Blöcke transformieren können.

Gutenberg Block-Transformation

Die Frage ist: was ist eine Transformation und warum benötigt man sie überhaupt?

Zum einen gibt uns Gutenberg die Möglichkeit, bereits bestehende Blöcke in andere über das Menü umzuwandeln. Das geht nur, wenn eine solche Regel erstellt wurde:

Menü zum Transformieren von Blöcken in Gutenberg.

Zum zweiten kann es sein, dass wir unseren Block in Zukunft ändern und er deswegen transformiert werden muss. Damit ein Benutzer am Ende nicht mit einem defekten Block da steht, sollte eine Regel für eine Transformation definiert werden.

Beispiel-Plugin

Ich habe ein Beispiel-Plugin vorbeireitet, bin dabei vorgegangen, wie im Kapitel “Einen Gutenberg Block programmieren” beschrieben und das ist entstanden:

<?php
/**
 * Plugin Name: mm Legend Block
 * Plugin URI:  https://wp-plugin-erstellen.de/ebook/block-apis/bloecke-transformieren/
 * Description: An easy Gutenberg Block for generating HTML legends.
 * Version: 0.1.0
 * Author: Florian Simeth
 */

add_action('init', 'mmfb_init');

function mmfb_init()
{
    wp_register_script(
        'mmfb-fieldset-block',
        plugin_dir_url(__FILE__) . 'js/fieldset.js',
        ['wp-blocks', 'wp-data', 'wp-editor', 'wp-i18n', 'wp-components'],
        filemtime(plugin_dir_path(__FILE__) . '/js/fieldset.js')
    );

    wp_enqueue_script('mmfb-fieldset-block');

    wp_register_style(
        'mmfb-fieldset-block',
        plugin_dir_url(__FILE__) . 'css/layout.css',
        [],
        filemtime(plugin_dir_path(__FILE__) . '/css/layout.css')
    );

    if (!is_admin() && is_singular()) {
        global $wp_query;
        $post = $wp_query->get_queried_object();
        if ($post instanceof WP_Post && has_block($post->post_content)) {
            #wp_enqueue_style('mmfb-fieldset-block');
        }
    }

    register_block_type(
        'mm/fieldset',
        [
            'style' => 'mmfb-fieldset-block',
        ]
    );
}
const {__} = wp.i18n;
const {registerBlockType} = wp.blocks;
const {RichText} = wp.blockEditor;

registerBlockType(
    'mm/fieldset',
    {
        title: 'Fieldset',
        category: 'widgets',
        icon: 'editor-kitchensink',
        keywords: [
            'MM',
            'Fieldset',
            'Label'
        ],
        supports: {
            multiple: true,
            align: true,
            className: true
        },
        attributes: {
            legend: {
                source: 'text',
                type: 'string',
                selector: 'legend'
            },
            content: {
                source: 'html',
                type: 'string',
                selector: 'div.content'
            }
        },
        edit: props => {
            const {attributes, setAttributes} = props;

            return <fieldset className="mm-fieldset">
                <RichText
                    tagName="legend"
                    value={attributes.legend}
                    placeholder={__('Enter a label', 'mfb')}
                    multiline={false}
                    onChange={(value) => {
                        setAttributes({legend: value})
                    }} /> <RichText
                tagName="div"
                className="content"
                value={attributes.content}
                placeholder={__('Enter some content', 'mfb')}
                multiline={false}
                onChange={(value) => {
                    setAttributes({content: value})
                }} />
            </fieldset>;
        },
        save: props => {
            const {attributes} = props;
            return <fieldset className="mm-fieldset">
                <RichText.Content tagName="legend" value={attributes.legend} /> <RichText.Content tagName="div"
                className="content" value={attributes.content} />
            </fieldset>
        }
    }
);
.mm-fieldset {
  border: 2px solid gray;
  padding: .5rem;
}

.mm-fieldset legend {
  box-sizing: border-box;
  color: inherit;
  display: table;
  max-width: 100%;
  white-space: normal;
  margin-top: -1.7rem;
  background-color: #fff;
  padding: 0 1rem;
}

.mm-fieldset .content {
  padding: 0 1rem;
}

Sie können das Beispiel-Plugin hier herunterladen.

Transformieren

Dem Beispiel oben können wir entnehmen, dass der Block folgenden Code erzeugt:

<fieldset class="mm-fieldset">
    <legend>Label 1</legend>
    <div class="content">Inhalt 1</div>
</fieldset>

Fall 1: Ändern des Ausgabe-Codes

Nehmen wir an, wir müssen aus irgend einem Grund, den Ausgabecode des Blocks verändern:

registerBlockType(
    'mm/fieldset',
    {
        ...
        save: props => {
            const {attributes} = props;
            return <div className="mm-fieldset">
                <fieldset className="mm-fieldset">
                    <RichText.Content tagName="legend" value={attributes.legend} /> <RichText.Content tagName="div"
                    className="content" value={attributes.content} />
                </fieldset>
            </div>
        }
    }
);

Es kommt also ein umrahmendes <div> drumherum. Ein Reload unserer erzeugt einen Fehler im Block:

Fehler: "Dieser Block enthält unerwarteten oder ungültigen Inhalt".

You’re not allowed to see this content. Please log in first.

Nach der Aktualisierung der Seite in der der Block integriert wurde, sehen wir in der JavaScript-Konsole eine Meldung:

Block successfully updated for `mm/fieldset` (...).

New content generated by `save` function:

<div class="wp-block-mm-fieldset mm-fieldset"><fieldset class="mm-fieldset"><legend>Label 1</legend> <div class="content">Enter 1</div></fieldset></div>

Content retrieved from post body:

<fieldset class="wp-block-mm-fieldset mm-fieldset"><legend>Label 1</legend> <div class="content">Enter 1</div></fieldset>

Fall 2: In andere Blöcke transformieren

Nun schauen wir den zweiten Fall an: wir wollen dem Benutzer die Möglichkeit geben, Blöcke in andere Umzuwandeln. Das schaffen wir mit der transform-Eigenschaft:

You’re not allowed to see this content. Please log in first.

Im obigen Beispiel definieren wir, dass unser Block in einen Paragraph-Block umgewandelt werden kann. Wir erhalten dann die Option, den Block in einen Paragraph-Block umzuwandeln:

Drop-Down "Umwandeln in" zeigt den Absatz-Block als Möglichkeit.

Fall 3: Von anderen Blöcken transformieren

Natürlich funktioniert das auch genau anders herrum. Beispielsweise Paragraph-Blöcke in den Fieldset-Block zu transformieren:

You’re not allowed to see this content. Please log in first.

Easy, oder? Gutenberg zeigt uns nun im Absatz-Block die Möglichkeit, in unseren Fieldset-Block umzuwandeln:

"Umwandeln in" Dropdown zeigt den Fieldset-Block als Option an.