In früheren Beiträgen in diesem Blog haben wir die Entwicklung von WordPress-Blöcken aus verschiedenen Blickwinkeln untersucht. Wir haben die Entwicklung von statischen und dynamischen Blöcken untersucht und die Funktionalität der Kernblöcke erweitert. Der Ansatz, den wir bisher verfolgt haben, hat es uns im Wesentlichen ermöglicht, Standardblöcke zu erstellen, die nicht in Echtzeit auf Nutzerinteraktionen reagierten. Kurz gesagt, diese Blöcke waren nicht interaktiv.

In diesem Artikel werden wir einen neuen Ansatz für die Entwicklung von Blöcken erkunden, mit dem wir dank einer neuen, leistungsstarken WordPress-API interaktive Blöcke erstellen können: die WordPress Interactivity API. Mit dieser API, die in WordPress 6.5 eingeführt wurde, kannst du Blöcke erstellen, die in Echtzeit auf Nutzerinteraktionen reagieren. So kannst du reichhaltige Nutzererlebnisse schaffen und deine Websites attraktiv, dynamisch und ansprechend gestalten.

Es gibt viel zu besprechen, aber bevor wir beginnen, werfen wir einen Blick auf die wichtigsten Voraussetzungen!

Was du brauchst, bevor du mit der Interactivity-API anfängst

Da die Interactivity-API auf React basiert, brauchst du zumindest Grundkenntnisse in serverseitigem JavaScript und React sowie in Build-Tools wie npm und npx. Außerdem brauchst du ein gutes Verständnis der WordPress-Entwicklung und des Gutenberg-Blockeditors.

Sobald du dir die nötigen Fähigkeiten angeeignet hast, brauchst du eine lokale Entwicklungsumgebung, mit der du schnell und einfach eine WordPress-Website starten kannst. Wir empfehlen DevKinsta, unsere lokale Entwicklungssuite, die speziell für WordPress entwickelt wurde. Mit DevKinsta kannst du mit wenigen Klicks eine neue lokale WordPress-Website einrichten und sie bis ins Detail anpassen.

Wenn du ein neues WordPress-Projekt in DevKinsta erstellst, kannst du die folgenden Optionen einstellen:

  • Top Level Domain: Standard .local
  • PHP-Version
  • Datenbankname
  • HTTPS aktivieren
  • WordPress Details
  • WordPress automatisch aktualisieren
  • Multisite

Außerdem kannst du eine bestehende MyKinsta-Website aus einem Backup importieren.

Konfigurieren einer lokalen Website in DevKinsta
Konfigurieren einer lokalen Website in DevKinsta

Was ist die Interactivity-API?

Die Interactivity-API ist eine WordPress-eigene API, mit der du Gutenberg-Blöcke und damit auch Beiträge und Seiten auf einer WordPress-Website mit Interaktivität versehen kannst. Es handelt sich um eine schlanke, moderne Lösung, die einen deklarativen Ansatz für die Verwaltung von Nutzerinteraktionen verfolgt.

Um einen interaktiven Block von Grund auf zu erstellen, sind fortgeschrittene PHP- und serverseitige JavaScript-Entwicklungskenntnisse erforderlich. Es ist jedoch nicht nötig, das Rad bei jedem neuen Projekt neu zu erfinden, da WordPress eine Vorlage für die Erstellung interaktiver Blöcke bereitstellt:

npx @wordpress/create-block --template @wordpress/create-block-interactive-template

Diese Vorlage enthält alles, was du brauchst, um einen interaktiven Block zu erstellen, einschließlich zweier funktionierender Beispiele, die du als Referenz für dein erstes Projekt verwenden kannst: eine Schaltfläche zum Umschalten des aktuellen Themes und eine Schaltfläche zum Erweitern/Klappen eines Absatzes.

Um loszulegen, öffne dein bevorzugtes Kommandozeilentool, navigiere zum Plugins-Verzeichnis deiner lokalen WordPress-Installation und gib Folgendes ein:

npx @wordpress/create-block your-interactive-block --template @wordpress/create-block-interactive-template

Warte ein paar Augenblicke, bis die Installation abgeschlossen ist, und öffne dann den Projektordner mit deinem bevorzugten Code-Editor. Wir empfehlen Visual Studio Code, aber du kannst auch den Editor verwenden, mit dem du dich am wohlsten fühlst.

Ein interaktiver Block in Visual Studio Code
Das interaktive Blockprojekt von @wordpress/create-block-interactive-template

Navigiere von der Kommandozeile aus zum Ordner des neuen Plugins und starte den Entwicklungsserver mit dem folgenden Befehl:

npm start

Von nun an werden alle Änderungen, die du an deinem Block vornimmst, in Echtzeit in deiner WordPress-Installation sichtbar sein.

Als Nächstes navigierst du in deinem WordPress-Admin zum Bildschirm Plugins und aktivierst das soeben erstellte Interactivity-API-Plugin. Erstelle einen neuen Beitrag oder eine neue Seite, suche dann im Block-Inserter nach deinem interaktiven Block und füge ihn zu deinem Inhalt hinzu. Speichere den Beitrag und zeige ihn in der Vorschau im Frontend an. Du wirst einen gelben Block mit zwei Schaltflächen sehen. Die erste Schaltfläche ändert die Hintergrundfarbe des Blocks und die zweite Schaltfläche zeigt oder verbirgt den Inhalt des Absatzes.

Ein Beispiel für einen interaktiven Block
Ein Beispiel für einen interaktiven Block, der von @wordpress/create-block-interactive-template bereitgestellt wird

Jetzt, wo du ein Plugin hast, auf das du dich für die in diesem Artikel behandelten Themen beziehen kannst, können wir weitergehen und interaktive Blöcke genauer untersuchen.

Die Struktur von interaktiven Blöcken

Der Aufbau von interaktiven Blöcken ist derselbe wie der von traditionellen Blöcken. Du brauchst immer noch eine package.json, eine block.json, eine edit.js und eine style.scss Datei. Zusätzlich brauchst du eine render.php Datei für das serverseitige Rendering und eine view.js Datei für die Interaktivität im Frontend.

Schauen wir uns die einzelnen Bausteine eines interaktiven Blocks an, indem wir die einzelnen Dateien des Starterprojekts aufschlüsseln.

package.json

Die Datei package.json wird in Node-Projekten verwendet, um dein Projekt zu identifizieren, Skripte zu verwalten und Abhängigkeiten während der Entwicklung zu verwalten und zu installieren.

Im Folgenden findest du die package.json für den interaktiven Block, die von der create-block-interactive-template bereitgestellt wird:

{
	"name": "your-interactive-block",
	"version": "0.1.0",
	"description": "An interactive block with the Interactivity API.",
	"author": "The WordPress Contributors",
	"license": "GPL-2.0-or-later",
	"main": "build/index.js",
	"scripts": {
		"build": "wp-scripts build --experimental-modules",
		"format": "wp-scripts format",
		"lint:css": "wp-scripts lint-style",
		"lint:js": "wp-scripts lint-js",
		"packages-update": "wp-scripts packages-update",
		"plugin-zip": "wp-scripts plugin-zip",
		"start": "wp-scripts start --experimental-modules"
	},
	"dependencies": {
		"@wordpress/interactivity": "latest"
	},
	"files": [
		"[^.]*"
	],
	"devDependencies": {
		"@wordpress/scripts": "^30.24.0"
	}
}

Die Abschnitte scripts und dependencies sind hier besonders wichtig.

  • build: Kompiliert den Quellcode in JavaScript für die Produktion. Die Option --experimental-modules aktiviert die Unterstützung für WordPress-Skriptmodule.
  • start: Startet den Entwicklungsserver. Beachte, dass die Option --experimental-modules erneut angegeben wird.
  • dependencies: Schließt Laufzeitabhängigkeiten mit dem neuesten Paket der Interactivity-API ein.

block.json

Die Datei block.json ist das Manifest für deinen Gutenberg-Block. Sie legt die zu ladenden Metadaten, Medien, Skripte und Stile fest. Standardmäßig generiert die create-block-interactive-template die folgende block.json:

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "create-block/your-interactive-block",
	"version": "0.1.0",
	"title": "Your Interactive Block",
	"category": "widgets",
	"icon": "media-interactive",
	"description": "An interactive block with the Interactivity API.",
	"example": {},
	"supports": {
		"interactivity": true
	},
	"textdomain": "your-interactive-block",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css",
	"render": "file:./render.php",
	"viewScriptModule": "file:./view.js"
}

Die folgenden Felder sind für einen interaktiven Block unerlässlich:

  • apiVersion: 3 ist die neueste Version der Block-API und unterstützt die neuesten Blockfunktionen, wie z. B. Skriptmodule.
  • supports: Gibt an, dass der Block unterstützt wird. "interactivity": true fügt Unterstützung für die Interactivity-API hinzu.
  • render: Gibt die PHP-Datei an, die für das Rendering im Frontend verantwortlich ist. In diese Datei fügst du die Direktiven ein, die einen Block interaktiv machen.
  • viewScriptModule: Legt die JavaScript-Datei fest, die die Interaktivitätslogik enthält. Diese Datei wird nur im Frontend geladen und nur, wenn die Seite den interaktiven Block enthält.

render.php

Auf render.php baust du das Markup für einen dynamischen Block auf. Um deinen Block interaktiv zu machen, musst du Attribute hinzufügen, die die DOM-Elemente deines Blocks interaktiv machen.

Die Datei render.php im Starterprojekt sieht wie folgt aus:

<?php
/**
 * PHP file to use when rendering the block type on the server to show on the front end.
 *
 * The following variables are exposed to the file:
 *     $attributes (array): The block attributes.
 *     $content (string): The block default content.
 *     $block (WP_Block): The block instance.
 *
 * @see https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#render
 */

// Generates a unique id for aria-controls.
$unique_id = wp_unique_id( 'p-' );

// Adds the global state.
wp_interactivity_state(
	'create-block',
	array(
		'isDark'    => false,
		'darkText'  => esc_html__( 'Switch to Light', 'your-interactive-block' ),
		'lightText' => esc_html__( 'Switch to Dark', 'your-interactive-block' ),
		'themeText'	=> esc_html__( 'Switch to Dark', 'your-interactive-block' ),
	)
);
?>

<div
	<?php echo get_block_wrapper_attributes(); ?>
	data-wp-interactive="create-block"
	<?php echo wp_interactivity_data_wp_context( array( 'isOpen' => false ) ); ?>
	data-wp-watch="callbacks.logIsOpen"
	data-wp-class--dark-theme="state.isDark"
>
	<button
		data-wp-on--click="actions.toggleTheme"
		data-wp-text="state.themeText"
	></button>

	<button
		data-wp-on--click="actions.toggleOpen"
		data-wp-bind--aria-expanded="context.isOpen"
		aria-controls="<?php echo esc_attr( $unique_id ); ?>"
	>
		<?php esc_html_e( 'Toggle', 'your-interactive-block' ); ?>
	</button>

	<p
		id="<?php echo esc_attr( $unique_id ); ?>"
		data-wp-bind--hidden="!context.isOpen"
	>
		<?php
			esc_html_e( 'Your Interactive Block - hello from an interactive block!', 'your-interactive-block' );
		?>
	</p>
</div>

Das macht dieser Code:

  • wp_interactivity_state: Ruft den globalen Ausgangszustand eines Interaktivitäts-API-Speicher ab und/oder setzt ihn.
  • data-wp-interactive: Aktiviert die Interactivity-API für das DOM-Element und seine Kinder. Sein Wert muss der eindeutige Namespace deines Plugins oder Blocks sein.
  • wp_interactivity_data_wp_context(): Erzeugt die Direktive data-wp-context, die einem bestimmten HTML-Knoten und seinen Kindern einen lokalen Status zuweist.
  • data-wp-watch: Führt einen Callback aus, wenn ein Knoten erstellt wird und jedes Mal, wenn sich der Status oder der Kontext ändert.
  • data-wp-class--dark-theme: Fügt dem HTML-Element die Klasse dark-theme hinzu oder entfernt sie.
  • data-wp-on--click: Führt den Code synchron zum Klick-Ereignis aus.
  • data-wp-text: Setzt den inneren Text des HTML-Elements.
  • data-wp-bind--aria-expanded und data-wp-bind--hidden: Setzt HTML-Attribute (aria-expanded und hidden) auf den entsprechenden Elementen basierend auf einem booleschen oder String-Wert.

view.js

Diese Datei definiert den Store, der die Logik und die Daten enthält, die für das Verhalten des Blocks benötigt werden, einschließlich Status, Aktionen und Rückrufe.

Im Folgenden findest du die Datei view.js, die vom Starterprojekt erstellt wurde:

/**
 * WordPress dependencies
 */
import { store, getContext } from '@wordpress/interactivity';

const { state } = store( 'create-block', {
	state: {
		get themeText() {
			return state.isDark ? state.darkText : state.lightText;
		},
	},
	actions: {
		toggleOpen() {
			const context = getContext();
			context.isOpen = ! context.isOpen;
		},
		toggleTheme() {
			state.isDark = ! state.isDark;
		},
	},
	callbacks: {
		logIsOpen: () => {
			const { isOpen } = getContext();
			// Log the value of `isOpen` each time it changes.
			console.log( `Is open: ${ isOpen }` );
		},
	},
} );
  • store: Die Hauptfunktion zum Erstellen und Registrieren des globalen Zustands und der Logik des Blocks.
  • getContext: Eine Funktion, die in Aktionen und Callbacks verwendet wird, um auf den lokalen Status (context) des DOM-Elements zuzugreifen, das das Ereignis ausgelöst hat.
  • state: Definiert die globalen reaktiven Daten des Blocks.
  • actions: Beinhaltet die Funktionen, die die Logik definieren und den Zustand ändern.
  • callbacks: Beinhaltet die Funktionen, die als Reaktion auf bestimmte Ereignisse oder Zustandsänderungen automatisch ausgeführt werden.

Das ist eine ganze Menge, aber keine Sorge! Alles wird klarer, wenn du die folgenden Abschnitte gelesen hast.

Schauen wir uns nun die wichtigsten Konzepte der Interactivity-API an: Direktiven, Speicher, Status, Aktionen und Rückrufe.

Interactivity-API-Direktiven

Wie andere Frontend-Bibliotheken, z. B. Alpine.js und Vue.js, verwendet die Interactivity API spezielle HTML-Attribute, mit denen du auf Ereignisse auf der Seite reagieren, den Zustand der Anwendung aktualisieren, das DOM manipulieren, CSS-Stile anwenden, Benutzereingaben verarbeiten und vieles mehr.

Diese Attribute werden Direktiven genannt und ermöglichen es dir, dein Markup mit der zugrunde liegenden JavaScript-Logik zu verbinden.

Im Folgenden findest du eine Liste der Direktiven, die du am häufigsten verwenden wirst.

Funktion Richtlinie Beschreibung
Aktivierung/Namensraum data-wp-interactive Aktiviert die API für das Element und seine Kinder. Der Wert muss auf den eindeutigen Bezeichner deines Plugins gesetzt werden.
Lokaler Zustand data-wp-context Liefert einen lokalen Status („Kontext“) für das aktuelle Element und alle seine Kinder. Er akzeptiert ein JSON-Objekt. Es wird empfohlen, wp_interactivity_data_wp_context() zu verwenden, um ihn in PHP zu setzen (typischerweise render.php).
Attribut-Bindung data-wp-bind--[attribute] Setzt ein HTML-Attribut (z. B. disabled, value) auf der Grundlage eines reaktiven Zustands- oder Kontextwerts (ein boolescher oder String-Wert).
Textmodifikation data-wp-text Setzt den inneren Textinhalt des Elements. Es werden nur Strings akzeptiert.
CSS-Klasse umschalten data-wp-class--[classname] Fügt in Abhängigkeit von einem booleschen Wert eine CSS-Klasse hinzu oder entfernt sie.
Inline-Styling data-wp-style--[css-property] Fügt eine Inline-Stilklasse in Abhängigkeit von einem booleschen Wert hinzu oder entfernt sie.
Ereignisbehandlung data-wp-on--[event] Führt Code als Reaktion auf Standard-DOM-Ereignisse wie click oder mouseover aus.
Initiale Ausführung data-wp-init Führt eine Callback-Funktion nur einmal aus, wenn der Knoten erstellt wird.
Zustandsbeobachtung data-wp-watch Führt einen Callback aus, wenn der Knoten erstellt wird und erneut, wenn sich der Zustand oder der Kontext ändert.
Liste Iteration data-wp-each Rendert eine Liste von Elementen.

Eine vollständige Liste der Direktiven findest du in den Entwicklungshinweisen zur Interactivity-API und in der API-Referenz.

Globaler Zustand, lokaler Kontext und abgeleiteter Zustand

Bevor du mit der Interactivity API beginnst, solltest du dich unbedingt mit den grundlegenden Konzepten der Zustandsverwaltung in der Frontend-Entwicklung vertraut machen. Diejenigen, die regelmäßig mit React, Vue oder Angular entwickeln, sind mit diesen Konzepten bereits vertraut. Für diejenigen, die mit diesen Technologien noch nicht vertraut sind, können einige allgemeine Definitionen hilfreich sein.

Globaler Zustand

Der globale Zustand ist die Menge an Daten, auf die fast alle Komponenten einer Anwendung zugreifen können. Im Fall der Interactivity-API wirkt sich der globale Status beispielsweise auf alle interaktiven Blöcke auf der Seite aus und hält sie synchronisiert. Wenn ein Nutzer z. B. ein Produkt in den Warenkorb legt, wird dies im Einkaufswagenblock angezeigt.

Wenn du die Interactivity-API verwendest, solltest du die Anfangswerte des globalen Zustands auf dem Server mit der Funktion wp_interactivity_state() festlegen. In dem oben beschriebenen Starterprojekt wird diese Funktion in der Datei render.php wie folgt verwendet:

// Adds the global state.
wp_interactivity_state(
	'create-block',
	array(
		'isDark'    => false,
		'darkText'  => esc_html__( 'Switch to Light', 'your-interactive-block' ),
		'lightText' => esc_html__( 'Switch to Dark', 'your-interactive-block' ),
		'themeText'	=> esc_html__( 'Switch to Dark', 'your-interactive-block' ),
	)
);

Diese Funktion nimmt zwei Argumente entgegen:

  • Einen eindeutigen Bezeichner für den Namespace der Filiale. In diesem Fall: create-block.
  • Ein Array mit Daten, die mit dem bestehenden Laden-Namensraum zusammengeführt werden, falls dieser existiert.

Die anfänglichen globalen Statuswerte werden dann zum Rendern der Seite verwendet. Du kannst direkt auf die globalen Statuswerte zugreifen, indem du state in den Werten der Direktivenattribute verwendest, wie im folgenden Code:

<button
	data-wp-on--click="actions.toggleTheme"
	data-wp-text="state.themeText"
></button>

Die Funktion store() bietet den Hauptzugriffspunkt auf den globalen Status von JavaScript, der auf den ausgewählten Namespace beschränkt ist. Zurück zum Code des Startprojekts: Die Funktion store() wird in der Datei view.js wie folgt verwendet:

import { store, getContext } from '@wordpress/interactivity';

const { state } = store( 'create-block', {
	state: { ... },
	actions: { ... },
	callbacks: { ... },
} );

Um auf den globalen Status zuzugreifen, kannst du die Eigenschaft state verwenden:

actions: {
	toggleTheme() {
		state.isDark = ! state.isDark;
	},
},

Lokaler Kontext

Lokaler Kontext sind Daten, auf die nur eine bestimmte Komponente und ihre direkten Kinder zugreifen können. Ein interaktiver WordPress-Block bietet einen unabhängigen Status für den Block und seine verschachtelten Elemente.

Wenn du die Interactivity-API verwendest, kannst du mit der Funktion getContext() auf den lokalen Kontext zugreifen. Wenn der Nutzer auf die Schaltfläche „Umschalten“ klickt, wird die Aktion toggleOpen() ausgelöst, die auf den lokalen Kontext der Komponente zugreift (siehe Starterprojekt):

actions: {
	toggleOpen() {
		const context = getContext();
		context.isOpen = ! context.isOpen;
	},
},
  • getContext(): Ruft das lokale Zustandsobjekt des Blocks ab. Die Eigenschaften dieses Objekts werden in der Komponentenbeschreibung (render.php) mit Hilfe der Funktion wp_interactivity_data_wp_context() definiert.
  • context.isOpen = ! context.isOpen;: Ändert den Wert der Eigenschaft isOpen im lokalen Kontext des Bausteins.

Abgeleiteter Zustand

Abgeleitete Zustände beziehen sich auf Daten, die dynamisch aus bestehenden globalen oder lokalen Zuständen berechnet werden.

Sieh dir zum Beispiel den Code in der Datei view.js an, und zwar in diesem Abschnitt:

const { state } = store( 'create-block', {
	state: {
		get themeText() {
			return state.isDark ? state.darkText : state.lightText;
		},
	},
	...
}

Dieser Block definiert den themeText abgeleiteten Zustand innerhalb des globalen Zustands, der im create-block Namespace definiert ist.

  • get themeText() ist kein fester Wert, sondern eine Funktion, die jedes Mal ausgeführt wird, wenn du versuchst, die Eigenschaft themeText zu lesen. Sie sollte nicht wie eine normale Funktion aufgerufen werden, da die Interactivity-API sie als Statuseigenschaft behandelt und ihren Wert automatisch neu berechnet, wenn sich die Werte anderer Statuseigenschaften ändern. Im obigen Code wird der Wert der Eigenschaft themeText jedes Mal neu berechnet, wenn sich der Wert der Eigenschaft isDark ändert. Wenn state.isDark gleich true ist, nimmt themeText den Wert von state.darkText an; andernfalls nimmt es den Wert von state.lightText an.

Einen umfassenderen Überblick über die in diesem Abschnitt beschriebenen Konzepte findest du unter Globalen Zustand, lokalen Kontext und abgeleiteten Zustand verstehen.

Aktionen und Rückrufe

Aktionen und Rückrufe bestimmen die Reaktion auf Benutzerinteraktionen und Zustandsänderungen.

Der Abschnitt actions eines interaktiven Blocks enthält Funktionen, die als Reaktion auf benutzergenerierte Ereignisse ausgeführt werden. Diese Funktionen dienen vor allem dazu, den lokalen oder globalen Zustand der Komponente zu ändern. Nimm den folgenden Code aus der Datei view.js:

actions: {
	toggleOpen() {
		const context = getContext();
		context.isOpen = ! context.isOpen;
	},
	...
},
  • In diesem Codeabschnitt verwendet die Funktion toggleOpen() getContext() , um auf den lokalen Kontext des Blocks zuzugreifen, der die Aktion ausgelöst hat, um den Wert der Eigenschaft isOpen zu ändern.

Auf ähnliche Weise kannst du auch auf den globalen Zustand zugreifen:

actions: {
	...,
	toggleTheme() {
		state.isDark = ! state.isDark;
	},
},
  • Die Funktion toggleTheme() greift direkt auf das globale Objekt state zu und ändert den Wert der Eigenschaft isDark.

Aktionen werden über die Direktive data-wp-on--[event] ausgelöst. In der Datei render.php findest du zum Beispiel die folgende Schaltfläche:

<button
	data-wp-on--click="actions.toggleOpen"
	data-wp-bind--aria-expanded="context.isOpen"
	aria-controls="<?php echo esc_attr( $unique_id ); ?>"
>
  • In diesem HTML-Code aktiviert das Attribut data-wp-on--click die Aktion toggleOpen, wenn der/die Nutzer/in auf die Umschalttaste klickt.

Der Abschnitt callbacks enthält Funktionen, die automatisch ausgeführt werden, wenn sich die Daten, von denen sie abhängen, ändern. Ihr Zweck ist es, als Reaktion auf eine Zustandsänderung Seiteneffekte zu erzeugen.

In dem von create-block-interactive-template generierten Basisprojekt findest du den folgenden Callback:

callbacks: {
	logIsOpen: () => {
		const { isOpen } = getContext();
		// Log the value of `isOpen` each time it changes.
		console.log( `Is open: ${ isOpen }` );
	},
},
  • Die Funktion logIsOpen verwendet die Variable isOpen, die im lokalen Kontext verfügbar ist.
  • Der Callback ruft den Wert von isOpen über getContext() ab.
  • Jedes Mal, wenn sich der Wert von isOpen ändert, gibt die Funktion eine Meldung an die Browserkonsole aus.
Eine Meldung in der Konsole sagt dir, dass sich der lokale Kontext geändert hat.
Eine Meldung in der Konsole informiert den Benutzer über die Änderung im lokalen Kontext

Wie man einen interaktiven Block baut

Jetzt, wo wir uns mit der Theorie beschäftigt haben, ist es an der Zeit, etwas Spaß mit dem Code zu haben! Im zweiten Teil dieses Leitfadens lernst du, wie du einen interaktiven Block erstellst, mit dem du Produkte zu einem idealen Warenkorb hinzufügen kannst, wobei sich die Mengen und Summen automatisch aktualisieren. Dies ist ein Demonstrationsbeispiel, aber wir hoffen, dass es dir ein klares Verständnis dafür vermittelt, wie du Zustände, Aktionen und Rückrufe nutzen kannst.

Der interaktive Block im Editor
Der interaktive Block im Editor

Wir werden einen Block namens Interaktiver Zähler mit Hilfe des create-block-interactive-template erstellen. Um loszulegen, öffne dein Kommandozeilentool und gib Folgendes ein:

npx @wordpress/create-block interactive-counter --template @wordpress/create-block-interactive-template

Als Nächstes navigierst du zu deinem neuen Projektverzeichnis und führst den ersten Build aus.

cd interactive-counter && npm run build

Öffne das Projekt jetzt in deinem Code-Editor. Im Verzeichnis /src suchst du nach der Datei block.json. Sie sollte in etwa so aussehen:

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "create-block/interactive-counter",
	"version": "0.1.0",
	"title": "Interactive Counter",
	"category": "widgets",
	"icon": "media-interactive",
	"description": "An interactive block with the Interactivity API.",
	"supports": {
		"interactivity": true
	},
	"textdomain": "interactive-counter",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css",
	"render": "file:./render.php",
	"viewScriptModule": "file:./view.js"
}

Du kannst sie gerne anpassen, aber achte darauf, dass du die oben beschriebenen wichtigen Felder nicht veränderst.

Die Datei edit.js

Der nächste Schritt ist die Erstellung des Blocks, der im Editor erscheinen wird. Hierfür musst du die Datei /src/edit.js bearbeiten. Öffne die Datei und ändere sie wie folgt:

import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.scss';

export default function Edit({ attributes, setAttributes }) {
	const blockProps = useBlockProps();
	const products = [
		{ id: 'product1', name: __('Product 1', 'interactive-counter'), price: 10.00 },
		{ id: 'product2', name: __('Product 2', 'interactive-counter'), price: 15.00 },
		{ id: 'product3', name: __('Product 3', 'interactive-counter'), price: 20.00 },
	];

	return (
		<div {...blockProps}>
			<h3>{__('Shopping Cart', 'interactive-counter')}</h3>
			<ul>
				{products.map((product) => (
					<li key={product.id} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
						<span style={{ flex: 1 }}>{product.name} - ${product.price.toFixed(2)}</span>
						<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
							<button disabled>-</button>
							<span>0</span>
							<button disabled>+</button>
						</div>
						<span style={{ flex: 1, textAlign: 'right' }}>
							{__('Subtotal:', 'interactive-counter')} $0.00
						</span>
					</li>
				))}
			</ul>
			<div style={{ borderTop: '1px solid #ccc', paddingTop: '15px' }}>
				<p style={{ display: 'flex', justifyContent: 'space-between' }}>
					<strong>{__('Subtotal:', 'interactive-counter')}</strong>
					<span>$0.00</span>
				</p>
				<p style={{ display: 'flex', justifyContent: 'space-between' }}>
					<strong>{__('Tax (22%):', 'interactive-counter')}</strong>
					<span>$0.00</span>
				</p>
				<p style={{ display: 'flex', justifyContent: 'space-between' }}>
					<strong>{__('Total:', 'interactive-counter')}</strong>
					<span>$0.00</span>
				</p>
			</div>
			<p>{__('Quantities and totals will be interactive in the frontend.', 'interactive-counter')}</p>
		</div>
	);
}

Dieser Code erzeugt einen eigenen Block im Backend. Der Block wird nur im Frontend interaktiv sein. Weitere Details zur Datei /src/edit.js findest du in unseren Gutenberg-Blockentwicklungsanleitungen.

Die Datei render.php

Die nächste Datei, die du bearbeiten musst, ist /src/render.php. Öffne die Datei und ersetze den bestehenden Code durch den folgenden:

<?php
/**
 * Render callback for the interactive-counter block.
 */

$products = [
	['id' => 'product1', 'name' => __('Product 1', 'interactive-counter'), 'price' => 10.00],
	['id' => 'product2', 'name' => __('Product 2', 'interactive-counter'), 'price' => 15.00],
	['id' => 'product3', 'name' => __('Product 3', 'interactive-counter'), 'price' => 20.00],
];

// Initialize global state
wp_interactivity_state('interactive-counter', [
	'products' => array_map(function ($product) {
		return [
			'id' => $product['id'],
			'name' => $product['name'],
			'price' => $product['price'],
			'quantity' => 0,
			'subtotal' => '0.00',
		];
	}, $products),
	'vatRate' => 0.22,
]);

Dieser Code macht Folgendes:

  • Zuerst wird ein fest kodiertes Array mit Produkten erstellt. Jedes Produkt hat eine ID, einen Namen und einen Preis.
  • Dann wird der globale Status mit wp_interactivity_state initialisiert. Der erste Parameter ist der Name des Ladens, der mit dem in view.js verwendeten Namen übereinstimmen muss.
  • Dann wird das vorherige Array mit den Produkten auf ein neues Array products abgebildet, wobei Menge und Zwischensumme zu den Eigenschaften des ursprünglichen Arrays hinzugefügt werden. Dieses neue Array bildet die Datenstruktur, die du in view.js verwenden wirst.
  • vatRate legt den Standardwert für die Steuerberechnung fest.

Als Nächstes fügst du dem obigen Code Folgendes hinzu:

<div <?php echo get_block_wrapper_attributes(); ?> data-wp-interactive="interactive-counter" data-wp-init="callbacks.init">
	<h3><?php echo esc_html__('Cart', 'interactive-counter'); ?></h3>
	<ul>
		<?php foreach ($products as $index => $product) : ?>
			<li data-wp-context='{
				"productId": "<?php echo esc_attr($product['id']); ?>",
				"quantity": 0,
				"subtotal": "0.00"
			}' 
			data-wp-bind--data-wp-context.quantity="state.products[<?php echo $index; ?>].quantity" 
			data-wp-bind--data-wp-context.subtotal="state.products[<?php echo $index; ?>].subtotal">
				<span class="product-name"><?php echo esc_html($product['name']); ?> - $<?php echo esc_html(number_format($product['price'], 2)); ?></span>
				<div class="quantity-controls">
					<button data-wp-on--click="actions.decrement">-</button>
					<span data-wp-text="context.quantity">0</span>
					<button data-wp-on--click="actions.increment">+</button>
				</div>
				<span class="product-subtotal">
					<?php echo esc_html__('Subtotal:', 'interactive-counter'); ?>
					$<span data-wp-text="context.subtotal">0.00</span>
				</span>
			</li>
		<?php endforeach; ?>
	</ul>
	<div class="totals">
		<p>
			<strong><?php echo esc_html__('Subtotal:', 'interactive-counter'); ?></strong>
			$ <span data-wp-text="state.subtotal">0.00</span>
		</p>
		<p>
			<strong><?php echo esc_html__('Tax (22%):', 'interactive-counter'); ?></strong>
			$ <span data-wp-text="state.vat">0.00</span>
		</p>
		<p>
			<strong><?php echo esc_html__('Total:', 'interactive-counter'); ?></strong>
			$ <span data-wp-text="state.total">0.00</span>
		</p>
	</div>
</div>

Das macht dieser Code:

  • Die Funktion get_block_wrapper_attributes() im Container div ist eine WordPress-Funktion, die die Standardattribute eines Blocks erzeugt. In diesem Fall erzeugt sie das Klassenattribut "wp-block-create-block-interactive-counter".
  • Das Attribut data-wp-interactive macht diesen Block interaktiv.
  • Das data-wp-init Attribut löst den init Callback aus, der in view.js definiert ist.
  • Die foreach Schleife erzeugt ein Listenelement für jedes Produkt im products Array.
  • data-wp-context definiert den lokalen Kontext für den Block.
  • data-wp-bind bindet den Wert von data-wp-context.quantity an die globale Eigenschaft state.products[$index].quantity.
  • Das Gleiche geschieht in der Zeile darunter mit der Zwischensumme.
  • Die folgenden beiden Schaltflächen aktivieren die Aktionen decrement und increment dank des Attributs data-wp-on--click.
  • Das Attribut data-wp-text im span aktualisiert den Inhalt des Elements auf der Grundlage des aktuellen Werts von context.quantity.

Der Rest des Codes ist selbsterklärend, also lass uns mit der nächsten Datei weitermachen.

Die Datei view.js

Diese Datei enthält die Logik für deinen interaktiven Block.

import { store, getContext } from '@wordpress/interactivity';

store('interactive-counter', {
	state: {
		get subtotal() {
			const { products } = store('interactive-counter').state;
			return products
				.reduce((sum, product) => sum + product.price * (product.quantity || 0), 0)
				.toFixed(2);
		},
		get vat() {
			const { subtotal, vatRate } = store('interactive-counter').state;
			return (subtotal * vatRate).toFixed(2);
		},
		get total() {
			const { subtotal, vat } = store('interactive-counter').state;
			return (parseFloat(subtotal) + parseFloat(vat)).toFixed(2);
		},
	},
	actions: {
		increment: () => {
			const context = getContext();
			const { products } = store('interactive-counter').state;
			const product = products.find(p => p.id === context.productId);
			if (product) {
				product.quantity = (product.quantity || 0) + 1;
				product.subtotal = (product.price * product.quantity).toFixed(2);
				context.quantity = product.quantity;
				context.subtotal = product.subtotal;
				console.log(`Incremented ${context.productId}:`, { quantity: product.quantity, subtotal: product.subtotal, context });
			} else {
				console.warn('Product not found:', context.productId);
			}
		},
		decrement: () => {
			const context = getContext();
			const { products } = store('interactive-counter').state;
			const product = products.find(p => p.id === context.productId);
			if (product && (product.quantity || 0) > 0) {
				product.quantity -= 1;
				product.subtotal = (product.price * product.quantity).toFixed(2);
				context.quantity = product.quantity;
				context.subtotal = product.subtotal;
				console.log(`Decremented ${context.productId}:`, { quantity: product.quantity, subtotal: product.subtotal, context });
			} else {
				console.warn('Cannot decrement:', context.productId, product?.quantity);
			}
		},
	},
	callbacks: {
		init: () => {
			const { products } = store('interactive-counter').state;
			products.forEach((product, index) => {
				product.quantity = 0;
				product.subtotal = '0.00';
				console.log(`Initialized product ${index}:`, { id: product.id, quantity: product.quantity, subtotal: product.subtotal });
			});
		},
	},
});

Diese Datei definiert den Speicher für den Namespace interactive-counter. Sie verwaltet Status, Aktionen und Rückrufe:

store('interactive-counter', {
	state: { ... },
	actions: { ... },
	callbacks: { ... },
});

Schauen wir uns das mal genauer an.

  • state: Definiert drei berechnete Statuseigenschaften (Getter): subtotal, vat, und total. Diese Funktionen rufen Werte aus dem globalen Zustand ab und berechnen die Werte, die zurückgegeben werden sollen.
  • actions: Definiert zwei Funktionen, die bei Ereignissen ausgeführt werden: increment und decrement. Diese Funktionen rufen das Array products aus dem globalen Zustand ab, rufen das aktuelle Produkt aus dem lokalen Kontext auf der Grundlage von context.productId ab, aktualisieren die Eigenschaftswerte des aktuellen Produkts (quantity und subtotal) und synchronisieren den lokalen Kontext mit den neuen Werten.
  • callbacks: Definiert einen init Callback für die Initialisierung.

Die folgende Abbildung zeigt den interaktiven Block im Frontend.

Ein interaktiver Zähler, der mit der Interactivity API erstellt wurde
Ein interaktiver Zähler, der mit der Interactivity API erstellt wurde

Zusammenfassung

In diesem Artikel haben wir die wichtigsten Funktionen der WordPress Interactivity API vorgestellt. Wir haben uns mit Schlüsselkonzepten wie dem globalen Zustand, dem lokalen Kontext, Direktiven, Aktionen und Callbacks beschäftigt. Du hast gelernt, wie du mit @wordpress/create-block-interactive-template einen interaktiven Block von Grund auf erstellst, und wir haben dies in die Praxis umgesetzt, indem wir einen echten Block erstellt haben, der mit Benutzereingaben interagiert.

Wir hoffen, dass wir dir die nötigen Werkzeuge und das Wissen vermittelt haben, um mit der WordPress Interactivity API fantastische, dynamische und interaktive WordPress-Websites zu erstellen.

Viel Spaß beim Programmieren!

Carlo Daniele Kinsta

Carlo ist ein leidenschaftlicher Liebhaber von Webdesign und Frontend-Entwicklung. Er beschäftigt sich seit über 10 Jahren mit WordPress, auch in Zusammenarbeit mit italienischen und europäischen Universitäten und Bildungseinrichtungen. Er hat Dutzende von Artikeln und Leitfäden über WordPress geschrieben, die sowohl auf italienischen und internationalen Websites als auch in gedruckten Magazinen veröffentlicht wurden. Du kannst Carlo auf X und LinkedIn finden.