Eigener Gutenberg-Block für 3D.
Shortcodes funktionieren, sind aber ein Relikt. Im Block-Editor von WordPress gehört eine 3D-Szene in einen eigenen Block: mit Mediathek-Auswahl, Einstellungen in der Seitenleiste und Skripten, die nur geladen werden, wo der Block wirklich steht. Diese Anleitung zeigt den modernen Aufbau.
Ein 3D-Block besteht aus einer block.json mit Attributen wie Modell-URL und Höhe, einem Editor-Skript für Auswahl und Einstellungen, einer render.php, die das HTML auf dem Server erzeugt, und einem viewScriptModule, das die 3D-Szene im Frontend startet. Seit WordPress 6.5 lädt WordPress dieses Modul automatisch nur auf Seiten, die den Block enthalten.
Warum ein Block statt Shortcode.
Ein Shortcode wie [modell_3d src="…" hoehe="480"] funktioniert in jeder WordPress-Version. Für Redakteure ist er aber unbequem: Parameter müssen auswendig gewusst werden, Tippfehler fallen erst in der Vorschau auf, und im Editor steht nur ein Stück Text statt einer Vorschau.
Ein eigener Block löst das:
- Auswahl aus der Mediathek statt URL abtippen.
- Einstellungen in der Seitenleiste — Höhe als Schieberegler, Drehung als Schalter, Hintergrund als Farbwähler.
- Vorschau im Editor mit dem Posterbild des Modells.
- Automatisches Laden: WordPress weiß, auf welchen Seiten der Block vorkommt, und lädt Skripte nur dort.
- Zukunftssicher: Blöcke funktionieren auch in Block-Themes, im Website-Editor und in Vorlagen.
Aufbau eines 3D-Blocks.
| Datei | Aufgabe |
|---|---|
block.json | Name, Attribute, Verweise auf alle anderen Dateien |
edit.js | Oberfläche im Editor: Mediathek-Auswahl, Einstellungen, Vorschau |
render.php | Erzeugt das HTML auf dem Server bei jedem Seitenaufruf |
view.js | Startet die 3D-Szene im Browser des Besuchers |
plugin.php | Registriert den Block in WordPress |
Ein wichtiger Architekturentscheid: Der Block wird dynamisch gerendert. Das bedeutet, der Editor speichert nur die Attribute, und das HTML wird bei jedem Aufruf von render.php erzeugt. Der Vorteil: Ändert sich später die Ausgabe — etwa ein neuer Viewer oder ein zusätzlicher Fallback —, gilt das sofort für alle Seiten, ohne dass jeder Block im Editor neu gespeichert werden muss. Bei statisch gespeicherten Blöcken führt jede Änderung am HTML zu der gefürchteten Meldung „Dieser Block enthält unerwarteten Inhalt“.
Schritt 1: block.json
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "manuel/modell-3d",
"title": "3D-Modell",
"category": "media",
"icon": "format-image",
"description": "Interaktives 3D-Modell mit Drehen, Zoomen und optional AR.",
"keywords": [ "3d", "glb", "modell", "three.js" ],
"attributes": {
"modellId": { "type": "number" },
"modellUrl": { "type": "string" },
"posterUrl": { "type": "string" },
"hoehe": { "type": "number", "default": 480 },
"drehen": { "type": "boolean", "default": true },
"ar": { "type": "boolean", "default": false },
"alt": { "type": "string", "default": "" }
},
"supports": { "align": [ "wide", "full" ], "spacing": { "margin": true } },
"editorScript": "file:./index.js",
"render": "file:./render.php",
"viewScriptModule": "file:./view.js",
"style": "file:./style-index.css"
}viewScriptModule wird seit WordPress 6.5 unterstützt und lädt ein ES-Modul nur auf Seiten mit diesem Block. Für ältere Versionen gibt es viewScript mit einem klassischen Skript. Die Dateinamen index.js und style-index.css entstehen beim Bauen mit @wordpress/scripts.
Schritt 2: Dynamisches Rendern mit render.php.
In render.php stehen die Attribute in der Variablen $attributes zur Verfügung. Die Funktion get_block_wrapper_attributes() ergänzt automatisch Klassen und Stile aus dem Editor, etwa Ausrichtung und Abstände. Wichtig: Das Posterbild und ein Textalternativ-Inhalt werden direkt im HTML ausgegeben — so sieht der Besucher sofort etwas, und Suchmaschinen sowie Screenreader bekommen eine Beschreibung.
<?php
if ( empty( $attributes['modellUrl'] ) ) {
return; // ohne Modell nichts ausgeben
}
$wrapper = get_block_wrapper_attributes( [
'class' => 'modell-3d',
'style' => sprintf( 'height:%dpx', absint( $attributes['hoehe'] ) ),
'data-src' => esc_url( $attributes['modellUrl'] ),
'data-drehen' => $attributes['drehen'] ? '1' : '0',
'data-ar' => $attributes['ar'] ? '1' : '0',
] );
?>
<figure <?php echo $wrapper; ?>>
<?php if ( ! empty( $attributes['posterUrl'] ) ) : ?>
<img class="modell-3d__poster" src="<?php echo esc_url( $attributes['posterUrl'] ); ?>"
alt="<?php echo esc_attr( $attributes['alt'] ); ?>" loading="lazy" decoding="async">
<?php endif; ?>
<button type="button" class="modell-3d__start">In 3D ansehen</button>
<?php if ( $attributes['alt'] ) : ?>
<figcaption class="screen-reader-text"><?php echo esc_html( $attributes['alt'] ); ?></figcaption>
<?php endif; ?>
</figure>get_block_wrapper_attributes gibt bereits maskierte Attribute zurück und darf deshalb direkt ausgegeben werden. Die Szene startet erst beim Klick auf den Button — das hält die Seite schnell und verhindert, dass Besucher unfreiwillig Megabytes laden.
Schritt 3: Die Szene im Frontend starten.
view.js sucht alle 3D-Blöcke auf der Seite und startet die Szene, sobald der Besucher klickt. Weil es ein ES-Modul ist, kann es Three.js oder model-viewer per import nachladen — erst in dem Moment, in dem es gebraucht wird. So kostet ein 3D-Block, der nie angeklickt wird, praktisch nichts.
document.querySelectorAll( '.modell-3d' ).forEach( ( el ) => {
const start = el.querySelector( '.modell-3d__start' );
if ( ! start ) return;
start.addEventListener( 'click', async () => {
start.disabled = true;
start.textContent = 'Lädt …';
// model-viewer erst jetzt laden
await import( 'https://ajax.googleapis.com/ajax/libs/model-viewer/4.0.0/model-viewer.min.js' );
const mv = document.createElement( 'model-viewer' );
mv.setAttribute( 'src', el.dataset.src );
mv.setAttribute( 'camera-controls', '' );
mv.setAttribute( 'touch-action', 'pan-y' );
if ( el.dataset.drehen === '1' ) mv.setAttribute( 'auto-rotate', '' );
if ( el.dataset.ar === '1' ) mv.setAttribute( 'ar', '' );
mv.style.cssText = 'width:100%;height:100%;';
mv.addEventListener( 'load', () => {
el.querySelector( '.modell-3d__poster' )?.remove();
start.remove();
} );
el.appendChild( mv );
} );
} );Für eine eigene Three.js-Szene wird statt model-viewer das eigene Szenenmodul importiert. Das Prinzip bleibt gleich: erst bei Bedarf laden, dann Poster und Button entfernen.
Schritt 4: Der Editor.
Im Editor-Skript entsteht die Oberfläche, die Redakteure sehen. Die wichtigsten Bausteine aus den WordPress-Paketen:
- MediaPlaceholder und MediaUpload für die Auswahl der GLB-Datei aus der Mediathek.
- InspectorControls für die Seitenleiste mit RangeControl (Höhe), ToggleControl (Drehen, AR) und TextareaControl (Beschreibung).
- useBlockProps, damit Ausrichtung und Abstände im Editor genauso wirken wie im Frontend.
Im Editor selbst sollte keine vollständige 3D-Szene laufen. Die Vorschau zeigt das Posterbild mit einem Hinweis. Das hält den Editor schnell, vor allem wenn mehrere 3D-Blöcke auf einer Seite stehen, und vermeidet Konflikte mit dem eingebetteten Editor-Fenster.
Ein Posterbild kann die Redaktion als Bild hochladen. Komfortabler ist ein Button „Poster erzeugen“, der das Modell im Editor kurz lädt, ein Bild aus der Szene erstellt und es in die Mediathek speichert. Das ist mehr Aufwand, erspart aber jedes Mal einen Screenshot.
Voraussetzung für die Mediathek-Auswahl: WordPress muss GLB-Dateien überhaupt annehmen. Wie das geht, steht im Ratgeber GLB-Dateien in WordPress hochladen.
Praxis: Vorschau, Barrierefreiheit, Caching.
- Poster immer setzen: Ohne Posterbild steht bis zum Klick eine leere Fläche auf der Seite. Das Posterbild ist außerdem das, was bei der Messung der Ladezeit als größtes Element zählt.
- Beschreibung pflegen: Das Feld für die Textbeschreibung sollte im Editor nicht optional wirken. Sie ist für Screenreader die einzige Information über das Modell.
- Tastatur: Der Start-Button ist ein echter Button und damit per Tastatur erreichbar. model-viewer unterstützt die Bedienung per Pfeiltasten.
- Optimierungs-Plugins: Viele Plugins behandeln ES-Module inzwischen korrekt, manche nicht. Nach Aktivierung von „JavaScript verzögern“ unbedingt testen, siehe 3D in WordPress schnell halten.
- Block-Vorlagen: Soll jede Produktseite einen 3D-Bereich haben, lässt sich der Block in eine Vorlage des Website-Editors oder in ein Block-Muster einbauen.
Wer nur ein Modell auf einer einzigen Seite zeigen will, braucht keinen eigenen Block — der eingebaute HTML-Block reicht. Ein eigener Block lohnt sich, sobald 3D auf vielen Seiten eingesetzt wird oder Redakteure ohne Code damit arbeiten sollen. Für Konfiguratoren ist er die Hülle, in der die eigentliche Anwendung sitzt.
Die Horizont-Baureise läuft eingebettet in einer WordPress-Website. Die übrigen Demos laufen als eigenständige Three.js-Anwendungen — technisch dieselbe Grundlage, die sich genauso in WordPress einbinden lässt. Die Markennamen sind überwiegend erfundene Showcases.
Nicht glauben — ausprobieren.
Alle Demos laufen live im Browser, auch auf dem Smartphone.
FAQ — Gutenberg-Block für 3D.
Wie baue ich einen eigenen Gutenberg-Block für 3D-Modelle?
Ein 3D-Block besteht aus einer block.json mit Attributen wie Modell-URL und Höhe, einem Editor-Skript mit Mediathek-Auswahl und Einstellungen, einer render.php, die das HTML auf dem Server erzeugt, und einem viewScriptModule, das die 3D-Szene im Frontend startet. Registriert wird er mit register_block_type in einem eigenen Plugin.
Warum sollte ein 3D-Block dynamisch gerendert werden?
Beim dynamischen Rendern speichert der Editor nur die Attribute, und das HTML wird bei jedem Aufruf neu erzeugt. Änderungen an der Ausgabe gelten dadurch sofort für alle Seiten, und die Meldung über unerwarteten Blockinhalt, die bei statisch gespeicherten Blöcken nach Änderungen auftritt, bleibt aus.
Was ist viewScriptModule?
Eine Angabe in der block.json, die seit WordPress 6.5 unterstützt wird. Sie verweist auf ein JavaScript-Modul, das WordPress nur auf Seiten lädt, auf denen der Block tatsächlich vorkommt. Innerhalb des Moduls können weitere Bibliotheken wie Three.js per import nachgeladen werden.
Sollte die 3D-Szene im Block-Editor laufen?
In der Regel nicht. Eine vollständige Szene im Editor macht ihn langsam, besonders bei mehreren Blöcken auf einer Seite. Besser ist eine Vorschau mit dem Posterbild und einem Hinweis, während die interaktive Szene nur im Frontend startet.
Wie verhindere ich, dass ein 3D-Block die Seite langsam macht?
Indem die Szene erst bei Klick oder bei Sichtbarkeit lädt und bis dahin ein Posterbild zeigt. Da das Frontend-Modul Bibliotheken per import erst bei Bedarf nachlädt, kostet ein nicht genutzter 3D-Block praktisch keine Ladezeit.
Brauche ich einen eigenen Block oder reicht der HTML-Block?
Für ein einzelnes Modell auf einer Seite reicht der eingebaute HTML-Block. Ein eigener Block lohnt sich, wenn 3D auf vielen Seiten eingesetzt wird, Redakteure ohne Code damit arbeiten sollen oder Einstellungen wie Höhe, Drehung und AR bequem wählbar sein sollen.
Funktioniert ein 3D-Block auch in Block-Themes?
Ja. Blöcke funktionieren in klassischen Themes mit Block-Editor ebenso wie in Block-Themes, im Website-Editor, in Vorlagen und in Block-Mustern.
Das bin ich – rechts im BildErzähl mir, was du zeigen willst.
Ich sage dir ehrlich, ob sich 3D für dein Vorhaben lohnt — und wenn nicht, was stattdessen mehr bringt.
Antwort meist innerhalb von 24 Stunden · hallo@manuelkillert.de

