Das Problem
Wer ACF Pro Blocks mit WYSIWYG-Feldern verwendet — insbesondere verschachtelt in Repeatern oder Groups — kennt vielleicht dieses frustrierende Verhalten: Du tippst Inhalte in ein WYSIWYG-Feld, klickst auf "Speichern", und nach dem Neuladen ist alles weg.
Der einzige Workaround, der bisher funktioniert hat: Vor dem Speichern den Block erst auf "Vorschau" umschalten. Vergisst du diesen Schritt, sind deine Inhalte verloren.
Betroffen: ACF Pro 6.7.x mit dem WordPress Block Editor (Gutenberg).
Warum passiert das?
ACFs Block-Integration funktioniert so:
- Wenn du einen ACF Block bearbeitest, leben die Feldwerte im DOM (Formular-Inputs, TinyMCE-Editoren)
- ACF lauscht auf
changeundkeyupEvents am Wrapper-Element des Blocks (.acf-block-fields) - Wenn ein Event erkannt wird, ruft ACF
acf.serialize()auf, um alle Feldwerte zu sammeln - Diese Werte werden per
setAttributes({ data })in den Gutenberg Store geschrieben - Beim Speichern persistiert WordPress die Block-Attribute (inklusive der serialisierten Daten)
Das Problem: TinyMCE rendert in einem iframe. DOM-Events aus dem iframe bubblen nicht zum übergeordneten Dokument hoch. Wenn du also in ein WYSIWYG-Feld tippst, feuert ACFs Change-Listener auf .acf-block-fields nie. Der Gutenberg Store behält die alten (leeren) Daten, und genau die werden gespeichert.
Text-Inputs, Selects und andere Nicht-iframe-Felder funktionieren einwandfrei, weil deren Events normal bubblen.
Wenn du in den Vorschau-Modus wechselst, serialisiert ACF explizit alle Felder — deshalb funktioniert es als manueller Workaround.
Die Lösung
Der Fix ist ein kleines JavaScript, das im Block Editor geladen wird. Es hakt sich in ACFs wysiwyg_tinymce_init Action ein, lauscht auf Content-Änderungen innerhalb von TinyMCE, schreibt den Inhalt per ed.save() zurück in die Textarea, und triggert dann ein change Event auf dem ACF Block Wrapper — genau dort, wo ACF bereits lauscht.
Das JavaScript
(function () {
if ( typeof acf === 'undefined' ) return;
acf.addAction( 'wysiwyg_tinymce_init', function ( ed ) {
var textarea = ed.getElement();
if ( ! textarea ) return;
var $blockWrapper = jQuery( textarea ).closest( '.acf-block-fields' );
if ( ! $blockWrapper.length ) return;
var syncTimer = null;
function syncContent() {
if ( syncTimer ) clearTimeout( syncTimer );
syncTimer = setTimeout( function () {
ed.save();
$blockWrapper.trigger( 'change' );
}, 300 );
}
ed.on( 'change keyup paste input undo redo', syncContent );
ed.on( 'blur', function () {
if ( syncTimer ) clearTimeout( syncTimer );
ed.save();
$blockWrapper.trigger( 'change' );
});
});
// Safety net: sync all editors on post save
if ( typeof wp !== 'undefined' && wp.data ) {
var isSaving = false;
wp.data.subscribe( function () {
var editor = wp.data.select( 'core/editor' );
if ( ! editor ) return;
var saving = editor.isSavingPost();
var autosaving = editor.isAutosavingPost();
if ( saving && ! autosaving && ! isSaving ) {
isSaving = true;
if ( typeof tinyMCE !== 'undefined' ) {
tinyMCE.triggerSave();
jQuery( '.acf-block-fields' ).trigger( 'change' );
}
}
if ( ! saving ) isSaving = false;
});
}
})();
So bindest du es ein
Speichere den Code als editor-wysiwyg-sync.js in deinem Plugin oder Theme und enqueue ihn auf enqueue_block_editor_assets:
add_action( 'enqueue_block_editor_assets', function() {
wp_enqueue_script(
'acf-wysiwyg-block-fix',
get_template_directory_uri() . '/assets/js/editor-wysiwyg-sync.js',
[ 'acf-input', 'wp-data' ],
'1.0.0',
true
);
});
Das war's. WYSIWYG-Felder in ACF Blocks speichern jetzt korrekt, ohne vorher auf Vorschau wechseln zu müssen.
Wie funktioniert der Fix im Detail?
Der Fix besteht aus zwei Teilen:
- Kontinuierlicher Sync: Über ACFs
wysiwyg_tinymce_initHook wird bei jeder TinyMCE-Instanz ein Event-Listener registriert. Aufchange,keyup,paste,input,undo,redoundblurwird der Inhalt pered.save()in die Textarea geschrieben und einchangeEvent auf dem nächsten.acf-block-fieldsWrapper getriggert — der Wrapper, auf dem ACFs eigener Serialisierungsmechanismus lauscht. - Safety Net beim Speichern: Zusätzlich lauscht das Script per
wp.data.subscribeauf den Speichervorgang. Wenn WordPress speichert (kein Autosave), wirdtinyMCE.triggerSave()aufgerufen und auf allen Block-Wrappern einchangegetriggert.
Wird ACF das fixen?
Wir haben ein GitHub Issue mit der vollständigen Root-Cause-Analyse und einem vorgeschlagenen Fix eingereicht. Hoffentlich wird das in ACF Core behoben. Bis dahin ist dieser Workaround stabil und nutzt ausschließlich ACFs eigene APIs — kein Hack, kein Monkey-Patching.
Umgebung
- ACF PRO 6.7.0.2
- WordPress 6.7.x – 6.9.x
- Getestet in Chrome und Firefox
- Reproduzierbar auf verschiedenen Hosting-Umgebungen (Raidboxes, Hetzner/nginx)

