Erstellen Sie ein großartiges WordPress-Bearbeitungserlebnis und sparen Sie Zeit mit Gutenberg InnerBlocks

Veröffentlicht: 2023-02-12

Wiederholen Sie sich nicht

Für Entwickler kann Faulheit eine Tugend sein. Eine gut gemachte, wiederverwendbare Komponente spart Zeit und ermöglicht eine effiziente Wiederverwendung und Konsistenz. Dies eignet sich gut zum Erstellen von Bearbeitungserfahrungen in WordPress, da Konsistenz Vertrautheit und Wissen für diejenigen schafft, die eine Website täglich nutzen.

WordPress hat mit der Veröffentlichung des Gutenberg-Blockeditors, der jetzt einfach als „The Editor“ bekannt ist, viel Aufsehen erregt. Für die Bearbeitung, Erstellung und Veröffentlichung von Inhalten bietet es eine hervorragende Erfahrung, weit besser als ältere WYSIWYGs. Als Entwickler möchte ich meinen Kunden das beste Bearbeitungserlebnis bieten, ich möchte die Kernfunktionalität nutzen und ich möchte das Rad nicht neu erfinden. Glücklicherweise lässt uns WordPress all diese Dinge mit benutzerdefinierten Blöcken tun.

Geben Sie InnerBlocks ein

InnerBlocks ist eine großartige Funktion im WordPress-Editor. Entwickler können Kernblöcke wie Absatz, Überschriften und Schaltflächen verwenden, um ein konsistentes Erlebnis für einen Kunden zu schaffen. Anstatt Textabschnitte neu zu schreiben und Felder neu zu deklarieren, erhält der Client eine Erfahrung, mit der er vertraut wird; Bearbeiten und Kombinieren derselben Blöcke. Werfen wir einen Blick auf einen Block, den wir möglicherweise für einen Kunden erstellen müssen, und sehen wir uns an, wie InnerBlocks uns dabei helfen kann, dies zu erreichen.

Einen Block mit InnerBlocks bauen

Ein Beispiel für einen Call-to-Action-Block mit Links zu Überschriften, Absätzen und Schaltflächen
Abbildung: ein Beispiel für einen Call-to-Action-Block. Dazu gehören eine Überschrift, ein Absatz und einige Schaltflächen-Links.

Lassen Sie uns diesen Block untersuchen und überlegen, wie wir ihn aufbauen könnten. Ein gängiges Werkzeug, nach dem wir beim Erstellen von Blöcken greifen, sind Advanced Custom Fields (ACF). ACF Pro fügt benutzerdefinierte Blockunterstützung hinzu, mit der Entwickler Blöcke in PHP für den Editor und das Frontend schreiben können. Außerdem können wir benutzerdefinierte Felder verwenden – ein Paradigma, mit dem viele WordPress-Entwickler vertraut sind. ACF unterstützt InnerBlocks, was bedeutet, dass wir einen benutzerdefinierten Block erstellen können, aber nicht einmal benutzerdefinierten Code für diese Überschrift, diesen Absatz oder diese Schaltflächen schreiben müssen.

Mit ACF-Blöcken können wir Kernblöcke nutzen, um ein großartiges Bearbeitungserlebnis für den gesamten Text zu schaffen, den wir in diesem Block sehen. Eine weitere mögliche Option wäre die Verwendung von Blockmustern, aber als Entwickler und Kuratoren einer fantastischen WordPress-Erfahrung erreicht das Erstellen eines benutzerdefinierten Blocks das gewünschte Ziel.

Registrierungscode blockieren

Hier ist der Code zum Registrieren unseres benutzerdefinierten ACF-Blocks. Lesen Sie hier mehr über die Verwendung der Funktion acf_register_block_type.

 <?php /** * Template for registering an ACF powered custom block. * * More info: https://www.advancedcustomfields.com/resources/blocks/ */ /** * Register the block. */ add_action( 'acf/init', function() { /** * ACF block registration options here: https://www.advancedcustomfields.com/resources/acf_register_block_type/ */ acf_register_block_type( array( 'name' => 'call-to-action-demo', // JS will register as: acf/{block-name}. 'title' => __( 'Call to Action ACF Demo', 'locale' ), 'description' => __( 'A custom ACF Call to Action block.', 'locale' ), 'render_template' => 'partials/blocks/call-to-action-demo.php', // Change to block template. 'category' => 'design', // Category in the block inserter. 'keywords' => array( 'action', 'buttons', 'cta' ), // Searchable keywords. 'supports' => array( 'align' => false, // Disable support for align. 'anchor' => true, // Enable support for anchor. 'jsx' => true, // Enable support for JSX. 'mode' => false, // Disable ACF block edit/preview mode switching as we are only using InnerBlocks for editable content. ), ) ); } );

Lassen Sie uns den Code aufschlüsseln. Wir verwenden die acf_register_block_type-Funktion, um unseren Block zu registrieren, und wir übergeben ein Array von Argumenten, die unseren Block definieren und die Funktionalität ein- und ausschalten.

  • Beachten Sie, dass wir dem empfohlenen Verfahren folgen, um einen eindeutigen Namen für unseren Block sowie einen für Menschen lesbaren Titel und eine Beschreibung hinzuzufügen. Wir verweisen auf ein Render-Template, wo wir später unser PHP-Template für den Block einrichten. Wir haben auch eine Kategorie hinzugefügt, in der unser Block im Block-Inserter gruppiert werden soll.
  • Wir haben durchsuchbare Schlüsselwörter, um die Suche nach dem Block im Inserter zu vereinfachen.
  • Wir fügen ein „supports“-Array hinzu, um Funktionen wie das Setzen eines HTML-Ankers zu ermöglichen, und wir haben die Ausrichtung deaktiviert, da dieser Block immer in der Mitte der Seite sitzt.
  • In diesem unterstützten Array schalten wir die Magie von InnerBlocks ein! Das Setzen von „jsx“ auf „true“ teilt ACF mit, dass wir das Rendern von React jsx-Templates innerhalb unseres Blocks unterstützen werden.

Lassen Sie uns den Inhalt überprüfen, den wir in unserem Block benötigen:

  • Überschrift
  • Absatztext
  • Schaltflächen zum Handeln!

Nun, normalerweise würden wir unserem Block Felder zuweisen, wie hier beschrieben. Aber in diesem Fall müssen wir das nicht – wir können Kernblöcke nutzen, um all dies zu erreichen. Wenn der Block beispielsweise einen Bildhintergrund benötigt, kann das Hinzufügen eines ACF-Bildfelds zum Block eine großartige Möglichkeit sein, dies zu erreichen. Bleiben wir jedoch zunächst bei unserem InnerBlocks-Beispiel und springen zur Vorlage.

Blockvorlage

Hier ist die Vorlage für den neuen Block. Stellen Sie sicher, dass die Blockregistrierung auf den Speicherort der Blockvorlage zeigt. Eine gängige Praxis besteht darin, diese in einem Partials-Ordner im Thema abzulegen.

 <?php /** * ACF Call to Action example block template. * * More info: https://www.advancedcustomfields.com/resources/acf_register_block_type/ * * @param array $block The block settings and attributes. * @param string $content The block inner HTML (empty). * @param bool $is_preview True during AJAX preview. * @param (int|string) $post_id The post ID this block is saved to. * */ // Create id attribute allowing for custom "anchor" value. $block_ . $block['id']; if ( ! empty( $block['anchor'] ) ) { $block_id = $block['anchor']; } // Create class attribute allowing for custom "className" and "align" values. $class_name = 'acf-call-to-action-demo'; if ( ! empty( $block['className'] ) ) { $class_name .= ' ' . $block['className']; } if ( ! empty( $block['align'] ) ) { $class_name .= ' align' . $block['align']; } ?> <div class="<?php echo esc_html( $class_name ); ?>"> <div class="cta__inner"> <?php // Set up innerBlocks and provide a template. // Restrict InnerBlocks to allowed block list. $allowed_blocks = array( 'core/heading', 'core/paragraph', 'core/buttons' ); // Start InnerBlocks with a template. $template = array( array( 'core/heading', array( 'placeholder' => __( 'CTA Heading', 'locale' ), 'align' => 'center', 'level' => '2', ), ), array( 'core/paragraph', array( 'placeholder' => __( 'Add CTA text here', 'locale' ), 'align' => 'center', ), ), array( 'core/buttons', array( 'placeholder' => __( 'Add CTA buttons here', 'locale' ), 'align' => 'center', ), array( array( 'core/button', array( 'text' => __( 'Take action', 'locale' ), ), ), array( 'core/button', array( 'text' => __( 'Learn more', 'locale' ), ), ), ), ), ); // Echo out our JSX InnerBlocks compoennt for the editor. echo '<InnerBlocks allowedBlocks="' . esc_attr( wp_json_encode( $allowed_blocks ) ) . '" template="' . esc_attr( wp_json_encode( $template ) ) . '" templateLock="false" />'; ?> </div> </div>

Lassen Sie uns diesen Code aufschlüsseln.

  • Am Anfang haben wir eine generische Blockvorlagen-Boilerplate, die ACF in ihrer Blockanleitung bereitstellt, wie z. B. Unterstützung für einen Anker und einen benutzerdefinierten Klassennamen.
  • Die InnerBlocks-Komponente kann Eigenschaften empfangen. Wir verwenden drei in dieser Vorlage.
    • Zulässige Blöcke: Wir fügen eine Reihe zulässiger Blöcke zum Kuratieren hinzu. Nur diese Blöcke stehen zur Auswahl im InnerBlocks-Bereich unseres benutzerdefinierten Blocks zur Verfügung.
    • Vorlage: Wir können ein Array von Blöcken übergeben und wir können Blockattribute übergeben, damit die Blöcke beginnen, wenn sie zum ersten Mal in den Editor geladen werden.
      • Beachten Sie, dass wir Blockattribute übergeben können, um unsere Benutzer auf Erfolg vorzubereiten. Für die Überschrift ist bereits Ebene 2 festgelegt, und der Absatz ist zentriert.
      • Hinweis: Kernblöcke werden in JavaScript immer als {plugin}/blockname bezeichnet. In unserem Fall verwenden wir Kernblöcke, aber wenn Sie einen benutzerdefinierten ACF-Block verwenden möchten, schreiben Sie „acf“ vor den Blocknamen. Denken Sie daran, dass wir bei der Verwendung von InnerBlocks diese Komponente an den WordPress-Editor übergeben, der React verwendet. Deshalb denken wir hier in JS.
      • Noch ein Hinweis: Beachten Sie, dass der Core/Buttons-Block InnerBlocks selbst verwendet! Wir passieren tatsächlich eine Reihe von zwei Kern-/Knopfblöcken darin!
    • Template-Sperre: templateLock wird für die InnerBlocks-Komponente festgelegt. Wenn wir es auf „alle“ setzen, könnte keiner der Blöcke in unserer Vorlage, die InnerBlocks zur Verfügung gestellt wird, verschoben oder entfernt werden. Wenn wir es auf „Einfügen“ setzen, können die Blöcke darin nur verschoben, keine Blöcke entfernt und keine neuen Blöcke hinzugefügt werden. Wenn wir es auf „false“ setzen, wird die InnerBlocks-Instanz entsperrt und sie wird unabhängig von übergeordneten Template-Sperren entsperrt (mehr dazu weiter unten). Lesen Sie mehr über Blockvorlagen im WordPress Block Editor Handbuch. Wir werden mehr über Blocksperren sprechen.

Wir haben einen neuen Block! Nach all dem und natürlich etwas Styling sieht der Beispielblock im Editor so aus:

Der Call-to-Action-Block mit ausgewähltem Überschriftenblock.
Abbildung: Der Call-to-Action-Block im Editor. Der Kopfzeilenblock ist ausgewählt.

Tiefer verschachteln: Mit verschachtelten InnerBlocks das Erlebnis noch besser kuratieren

Wir haben einen großartigen Block, und wir mussten kein WYSIWYG einrichten oder sogar benutzerdefinierte Felder in unserer Vorlage bearbeiten. Aber was wäre, wenn wir diese Erfahrung für den Kunden noch weiter kuratieren und verfeinern wollten? Angenommen, wir erhalten eine Anfrage, dass wir sicherstellen sollen, dass die Überschrift immer vorhanden ist, also gibt es immer einen Überschriftenblock, aber der Inhalt danach ist flexibel und könnte sogar eine Liste oder einen anderen Blocktyp enthalten. Unser Ziel ist es, diese Flexibilität zu erreichen und gleichzeitig die Konsistenz zu wahren.

Betrachten wir einige Regeln bei der Arbeit mit InnerBlocks:

  • Ein einzelner Block darf nur eine Instanz von InnerBlocks enthalten.
  • Mehrere Blöcke innerhalb von InnerBlocks können ihre eigenen InnerBlocks-Komponenten verwenden.
  • InnerBlocks können über die Eigenschaft templateLock gesperrt werden, aber Instanzen von InnerBlocks, die tiefer in einer verschachtelten Blockstruktur liegen, können wieder entsperrt werden, indem man templateLock auf false setzt.

Eine Lösung besteht darin, einen neuen Block zu erstellen, der als Wrapper für InnerBlocks dient. Wir würden diesen Block in unsere übergeordnete Blockvorlage aufnehmen und sperren, aber unseren Wrapper-Block darin explizit entsperren, indem wir „templateLock“ auf „false“ setzen. Möglicherweise möchten wir auch sicherstellen, dass dieser spezielle Wrapper-Block nur innerhalb des von uns ausgewählten übergeordneten Blocks verfügbar ist, indem wir einen übergeordneten Block für unseren Block festlegen. Wir könnten mehrere Blocktypen innerhalb dieses Bereichs zulassen, um Redakteuren Listen und mehr anzubieten, während wir immer noch nur die Überschrift, Schaltflächen und unseren Wrapper-Block im übergeordneten Call-to-Action-Block zulassen.

Einzelne Blockverriegelung

Eine neue Funktion in WordPress 5.9 ist die Möglichkeit, einzelne Blöcke in einem Template zu sperren. Dies ist eine weitere mögliche Lösung für unser flexibles, aber konsistentes Problem.

So sieht unsere Vorlage aus, wenn einige einzelne Blöcke gesperrt sind:

 <?php /** * ACF Call to Action example block template. * * More info: https://www.advancedcustomfields.com/resources/acf_register_block_type/ * * @param array $block The block settings and attributes. * @param string $content The block inner HTML (empty). * @param bool $is_preview True during AJAX preview. * @param (int|string) $post_id The post ID this block is saved to. * */ // Create id attribute allowing for custom "anchor" value. $block_ . $block['id']; if ( ! empty( $block['anchor'] ) ) { $block_id = $block['anchor']; } // Create class attribute allowing for custom "className" and "align" values. $class_name = 'acf-call-to-action-demo'; if ( ! empty( $block['className'] ) ) { $class_name .= ' ' . $block['className']; } if ( ! empty( $block['align'] ) ) { $class_name .= ' align' . $block['align']; } ?> <div class="<?php echo esc_html( $class_name ); ?>"> <div class="cta__inner"> <?php // Set up innerBlocks and provide a template. // Restrict InnerBlocks to allowed block list. $allowed_blocks = array( 'core/heading', 'core/paragraph', 'core/buttons' ); // Start InnerBlocks with a template. $template = array( array( 'core/heading', array( 'placeholder' => __( 'Heading', 'locale' ), 'align' => 'center', 'level' => '2', 'lock' => array( 'move' => true, // Block may nto be moved. 'remove' => true, // Block may not be removed. ), ), ), array( 'core/paragraph', array( 'placeholder' => __( 'Add CTA text here', 'locale' ), 'align' => 'center', ), ), array( 'core/buttons', array( 'placeholder' => __( 'Add CTA buttons here', 'locale' ), 'align' => 'center', 'lock' => array( 'move' => true, // Block may not be moved. 'remove' => true, // Block may not be removed. ), ), array( array( 'core/button', array( 'text' => __( 'Take action', 'locale' ), ), ), array( 'core/button', array( 'text' => __( 'Learn more', 'locale' ), ), ), ), ), ); // Echo out our JSX InnerBlocks compoennt for the editor. echo '<InnerBlocks allowedBlocks="' . esc_attr( wp_json_encode( $allowed_blocks ) ) . '" template="' . esc_attr( wp_json_encode( $template ) ) . '" />'; ?> </div> </div>

Die Überschrift und die Schaltflächenblöcke sollten nicht mehr verschoben oder entfernt werden können. Aktualisieren Sie unbedingt den Editor, entfernen Sie den Block und fügen Sie ihn dann erneut hinzu, um die Vorlagenänderungen zu erhalten.

Bonus: Den gleichen Block nativ erstellen

Sobald Sie einen Build-Prozess eingerichtet haben, ist das Erstellen nativer WordPress-Blöcke mit React überraschend einfach und unterscheidet sich nicht allzu sehr vom Erstellen eines Blocks in PHP. Das Einrichten einer Blockentwicklungsumgebung würde den Rahmen dieses Artikels sprengen, aber es gibt eine Reihe von Ressourcen, die Ihnen den Einstieg erleichtern, wie z. B. das WordPress Block Editor Handbook. Sobald Sie in der Lage sind, benutzerdefinierte Blöcke einzufügen, können Sie mit InnerBlocks schnell Blöcke erstellen.

Hier ist ein Beispiel für unseren Call-to-Action-Block index.js in React. Sie werden dieselbe Strategie sehen, die wir oben mit ACF besprochen haben, die hier angewendet wird.

 import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; import { InnerBlocks } from '@wordpress/block-editor'; import { useBlockProps } from '@wordpress/block-editor'; /** * Block Name. * Create an example Call to Action Block * Uses InnerBlocks for editable content within. */ export const blockName = 'call-to-action'; /** * Block Config. * Set basic params for controlling the editor. */ export const BLOCK_CONFIG = { // Set up the block template. CTA_TEMPLATE: [ [ 'core/heading', { placeholder: __('CTA Headline', 'locale'), align: 'center', level: 2, lock: { move: true, remove: true, }, }, ], [ 'core/paragraph', { placeholder: 'Optional CTA text', align: 'center', lock: { move: true, }, }, ], [ 'core/buttons', { lock: { move: true, remove: true, }, className: 'is-content-justification-center', align: 'center', // __experimentalLayout - https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/buttons/block.json layout: { type: 'flex', justifyContent: 'center', }, }, [ [ 'core/button', { text: 'Apply now', lock: { move: true, remove: true, }, }, ], ['core/button', { text: 'Learn more' }], ], ], ], // Set up the allowed blocks. ALLOWED_BLOCKS: ['core/paragraph', 'core/heading', 'core/buttons'], }; // Register the block via WP func. Change 'myplugin' to your plugin or theme. registerBlockType(`myplugin/${blockName}`, { title: __('Call to Action', 'locale'), // Change 'locale' to your locale for internationalization. description: __( 'Call to action block with headline and buttons', 'locale' ), keywords: [__('call'), __('action'), __('cta')], category: 'design', supports: { anchor: true, defaultStylePicker: false, html: false, align: false, }, attributes: { anchor: { type: 'string', default: '', }, }, transforms: {}, variations: [], edit: (props) => { const blockProps = useBlockProps({ className: `wp-block-myplugin-${blockName}`, }); return ( <div {...blockProps}> <div className="cta__inner"> <div className="cta__inner-blocks-wrapper"> <InnerBlocks template={BLOCK_CONFIG.CTA_TEMPLATE} allowedBlocks={BLOCK_CONFIG.ALLOWED_BLOCKS} renderAppender={false} /> </div> </div> </div> ); }, save: () => { return ( <div> <div className="cta__inner"> <InnerBlocks.Content /> </div> </div> ); }, });

Geh hin und baue!

Zusätzliche Ressourcen

  • Bill Ericksons Artikel über InnerBlocks
  • Bill Ericksons Artikel über den Blockeditor
  • Leitfaden für ACF-Blöcke
  • Dokumentation zum ACF-Registerblocktyp
  • WordPress-Blockeditor-Handbuch
  • WordPress Block Editor Handbuch: Erstellen Sie ein Block-Tutorial