Ich bin Freund von feingliedriger Datenverwaltung und so kommen bei dem meisten meiner Projekte Custom Fields zum Einsatz. Ich glaube, dass es für die Anwender:innen viel angenehmer ist Daten strukturiert einzugeben und ich habe viel mehr Freiheit bei der Gestaltung und Anpassung von Layouts.
Custom Fields?!
„Custom Fields“ – zu Deutsch „benutzerspezifische Felder“ – sind eine Weise in WordPress Informationen zu verwalten. Statt z. B. einen Termin in einem Kalender als reines Textdokument zu verstehen können Startzeit, Endzeit, Veranstaltungsort usw. in differenzierten Feldern gespeichert werden und damit überhaupt erst wirklich verwaltet werden.
Gutenberg?!
WordPress hat mit Version 5.0.0 einen neuen Editor bekommen mit dem Codenamen (… haha …) Gutenberg.
Der bisherige Editor hatte keinen Namen, weil es einfach „der Editor“ war. Wer bewusst die gewohnte Weise Inhalt zu verwalten verwenden will verwendet z. B. das Plugin Classic Editor oder sorgt dafür, dass WordPress Gutenberg nicht laden kann (z. B. durch deaktivieren der REST-API).
Wie es bisher ging
Bisher habe ich Custom Fields fast immer mittels Advanced Custom Fields (kurz ACF) gelöst.
Ich bin nicht der größte Fan des Plugins und habe immer mal wieder Alternativen wie Metabox, CMB2 und – mein aktueller Favorit als potentielle Alternative carbon fields – angeguckt. Bin allerdings immer wieder bei ACF gelandet. Es ist halt doch einfach der Platzhirsch und weit unterstützt.
Allerdings verwende ich es gerne mit einem Hilfsscript, das die Felddefinition via Code angenehmer macht.
Hier ein Beispiel, wie das aussehen könnte:

Vielleicht liegt es nur daran, dass ich diesen Anblick gewohnt bin – es wirkt recht aufgeräumt für mich.

In Gutenberg sieht es garnicht so schlecht aus – wenn die Felder angezeigt werden und wenn man davon absieht, dass oben das Content-Feld eigentlich unnötig ist.
Wenn ich in meinem Post-Type das Editor-Feld deaktiviere fällt WordPress automatisch auf den Classic Editor zurück.
Wieso überhaupt Gutenberg, wenn mir die Ansicht im Classic Editor doch gefällt?
Der Classic Editor hat offizielles End of Life – also Ende der offiziellen Unterstützung – Ende 2021. Das Projekt, das ich baue, soll für die nächsten Jahre funktionstüchtig sein. Also sollte ich lieber jetzt eine Lösung bauen, die längerfristig funktioniert.
Statt Custom Fields Custom Block
Meine Strategie ist jetzt statt „unten“ Custom Fields zu haben mit einem Block/Blöcken zu arbeiten.
ACF ist da gerne hilfreich, aber es gibt auch andere Plugins. Lazy Blocks ist mir das gestern aufgefallen, hab es aber noch nicht so richtig getestet.
Also registriere ich meinen Block via ACF – Anleitungen auf Englisch:
Auf der ACF-Webseite
Bei Bill Erickson, dessen Anleitungen sehr hilfreich waren.
Super – dann sieht es schon recht elegant aus und ich habe keine doppelte Struktur zwischen Content und Feldern mehr.

Allerdings muss der Block manuell hinzugefügt werden und ich hab keine Kontrolle darüber, wie davor und danach Inhalte angezeigt werden.
Schön ist aber, dass die Vorschau des Blocks die selbe Optik hat wie der Block im Frontend angezeigt werden wird. Dadurch kann grafisch beigetragen werden, dass die Felder einfacher zu verstehen sind.
Um zu ersparen, dass der Block manuell angelegt werden muss und auch um die Reihenfolge/Vollständigkeit der Blöcke zu gewährleisten, gibt es eine Möglichkeit die in der Gutenberg Dokumentation gut beschrieben wird.
Hier der Quelltext aus dem Beispiel – etwas aufgefrischt von mir.
function csc_register_speaker_speaker_type() {
$args = [
'public' => true,
'label' => __('Speaker', 'csc'),
'show_in_rest' => true,
'template' => [
[ 'core/image', [
'align' => 'left',
] ],
[ 'core/heading', [
'placeholder' => __('Add Author...', 'csc'),
] ],
[ 'core/paragraph', [
'placeholder' => __('Add Description...', 'csc'),
] ],
],
'template_lock' => 'all',
];
register_post_type( 'speaker', $args );
}
add_action( 'init', 'csc_register_speaker_post_type' );
Code-Sprache: PHP (php)
In der Registrierung von Custom Post Types kann der neue Parameter template
verwendet werden, um Blöcke als Standard-Vorlage zu definieren. Interne Blöcke, ACF Blöcke, Drittanbieter-Blöcke. Dort kann ich meinen acf-Block angeben und somit wird mein Inhaltstyp direkt mit der Templatevorlage befüllt.
Mit template_lock
kann ich via ‚all'
bestimmen, dass meine Block-Vorgabe fixiert ist oder via ‚insert'
vorgeben, dass die vorgegebenen Blöcke zwar nicht gelöscht, aber weitere hinzugefügt werden dürfen.
Für reine Darstellungsinhalte bin ich damit fertig. Die Gestaltung meiner Inhalte kommt durch das am Block definierte Template. Und eigentlich brauche ich für den Weg nicht mal ACF. Ich kann mit evtl. ein Template aus dem Core-Blöcken zusammen bauen.
Bei meinem Auftrag will/brauch ich tatsächlich Meta-Felder, weil ich Inhalte miteinander verknüpfe und auch manche Infos auf Übersichtsseite zusammenfasse.
Wo speicher ACF die Daten des Blocks?
Leider speichert ACF die Daten des Blocks nicht wie gewohnt in de Post-Meta-Tabelle aus der sich leicht mit get_field()
oder get_post_meta()
geholt werden können.
Das könnte für mich ein Grund sein, mir Alternativen zu suchen. Lazy Blocks bietet z. B. die Möglichkeit an, Formulareingaben als Post-Meta zu speichern. So wie ich es mir von Custom Fields wünschen würde.
Aber naja – Blöcke sind keine Custom Fields – ich verwende den Block ja eigentlich auch falsch.
Also, wie werden die Daten gespeichert?
Also HTML-Kommentar an die Block-Infos in den Post-Inhalt. So wie andere Gutenberg-Blöcke das auch tun.
<!-- wp:acf/speaker {"id":"block_607352f190fe6","name":"acf/speaker","data":{"field_60734693ebf6e":"Sebastian","field_6073469cebf6f":"Webdevelopment","field_607346a1ebf70":"Germany","field_607346a5ebf71":"","field_607346baebf72":"","field_607346e7ebf73":"No Poverty","field_60734736ebf74":""},"align":"","mode":"edit"} /-->
Code-Sprache: HTML, XML (xml)
So sieht das dann z. B. aus. Und ACF lässt sich da auch nicht mit sich verhandeln, dass ich die Daten gerne zwischenspeichern will.
Bill Erickson kommt wieder zur Hilfe und erklärt, wie Block-Daten mittels parse_blocks
geparst werden können.
Ich nutze das Wissen, um beim Speichern des Inhaltes die Block-Daten auszulesen und in die Datenbank zu schreiben (vermutlich sollte hier noch ordentliches Escaping eingeführt werden).
function save_speaker_block_data_to_meta( $post_id, $post) {
$blocks = parse_blocks( $post->post_content );
$data = [];
foreach( $blocks as $block ) {
if( 'acf/speaker' === $block['blockName'] ) {
$data = $block['attrs']['data'];
break;
}
}
if ( empty( $data ) ) {
return;
}
update_post_meta( $post_id, 'name', $data['name'] );
update_post_meta( $post_id, 'country', $data['country'] );
update_post_meta( $post_id, 'expertise', $data['expertise'] );
}
add_action( 'save_post_speaker', 'save_speaker_block_data_to_meta', 10, 2 );
Code-Sprache: PHP (php)
Kommt mir alles noch nicht so ideal vor.
Aber mal ein erster Umgang mit Gutenberg und Custom Fields.
Ich werde mich in der nächsten Zeit umsehen, was andere Plugins in der neuen Gutenberg-Welt so zu bieten haben und vielleicht führt mein Weg ja weg von ACF.
Update – hacky workaround
Ok – ich finde das für das aktuelle Projekt doch ein bisschen mühselig und hab mich entschieden, dass ich doch – wie üblich – mit regulären ACF-Feldern arbeiten will.
Trotzdem soll es Gutenberg sein, damit die User:innen nicht bei jedem Inhaltstypen ein anders Interface haben.
Die ACF-Felder werden ja inzwischen ganz ok angezeigt – siehe Screenshot oben. Allerdings stört mich das Textfeld, dass ich nicht verwenden will. An der Stelle mag ich es auch nicht für z. B. den Haupt-Text-Inhalt verwenden, weil die Reihenfolge dafür nicht stimmig ist.
Meine Lösung: Ich arbeite mit template
und template_lock
in der register_post_type
-Definiton – allerdings mit dem Ziel die minimale Ausgabe zu erlauben:
function csc_register_speaker_speaker_type() {
$args = [
'public' => true,
'label' => __('Speaker', 'csc'),
'show_in_rest' => true,
'template' => [
[ 'core/separator' ],
],
'template_lock' => 'all',
];
register_post_type( 'speaker', $args );
}
add_action( 'init', 'csc_register_speaker_post_type' );
Code-Sprache: PHP (php)
Damit wird nur eine kleine Seperator-Linie angezeigt. Die potentiell auch noch auf weiß gesetzt werden könnte.
Ideal ist anders – aber zumindest extrem simpel.
Robert meint
Hallo Sebastion,
eine gute Option den Block-Inserter für Custom Post Types zu deaktivieren ist folgende:
function manage_allowed_blocks( $allowed_block_types, $block_editor_context ) {
$post_type = $block_editor_context->post->post_type;
if ($post_type == ‚custom-post-type‘) {
$allowed_block_types = false; }
return $allowed_block_types;
}
add_filter( ‚allowed_block_types_all‘, ‚manage_allowed_blocks‘, 10, 2 );
Zu finden in der WP Dokumentation unter https://developer.wordpress.org/reference/hooks/allowed_block_types_all/
Dadurch hat man zwar das Gutenberg Interface (wenn im Post Type unterstützt) aber der Block Editor ist leer.
Beste Grüße,
Robert
Sebastian Gärtner meint
Cool – danke für die Ergänzung!
ts meint
Hi.
Ich glaube, seit Version 5.11 erlaubt ACF per REST API auf die Custom Fields zuzugreifen.
Damit müsste man zumindest mit einem selbstgebauten nativen Block Daten als Custom-Fields im post-meta speichern können, sinnvoll zumindest solange es nur einen entsprechenden Block per Post/Typt gibt, also s.o. mit gelocktem Block Template. Dann hätte man das Szenario „Front-End-gestylte Input-Maske“.
Ob das auch mit der Blockregistrierung über die ACF-Blockfunktionen gilt konnte ich aus der Dokumentation nicht entnehmen.
Sebastian Gärtner meint
Also aus ACF-Blöcken heraus Meta-Daten zu speichern klappt bisher wie im Artikel beschrieben ausreichend gut.
Tatsächlich hab ich mich jetzt mit nativen Blöcken beschäftigt – also direkt in JavaScript.
Und finde das ca ähnlich einfach/kompliziert wie ACF-Blöcke, allerdings ist das Ergebnis deutlich besser.
Weil in-place-editing, schnelleres Laden usw.
Und Werte als Meta-Daten zu speichern ist trivial.
Von daher gehe ich vermutlich ab jetzt den nativen Weg.
Trotz Life-Time-Lizenz rückt ACF damit weiter aus meiner Liste der essentiellen Plugins. Und ich finde es gut.
Mich nervt schon lange, dass Post-Meta immer doppelte Datenbank-Zeilen verursachen. Aber die Alternativen zu ACF haben mir bisher alle schlechter gefallen.
nin meint
Hallo, das würde mich interressieren. Kannst du dazu villeicht mal einen Beitrag machen? Also, wie du die Blöcke jetzt einbaust? LG
Sebastian Gärtner meint
Du meinst vermutlich, wie ich native Blöcke baue?
Ehrlich gesagt hab ich mir da ca. 10 – 20 Tutorials zusammen gesammelt.
Die offizielle Dokumentation ist teilweise nicht vollständig und teilweise nicht sehr verständlich.
Trotzdem unverzichtbar: https://developer.wordpress.org/block-editor/
Misha war wichtig für mich: https://rudrastyh.com/
Und https://awhitepixel.com/blog/ hatte einiges hilfreiches.
Ach ja, und die React-Doku natürlich: https://reactjs.org/docs/jsx-in-depth.html
Dann noch diese tolle Übersicht über die Komponenten, die so zur Verfügung stehen: https://wp-gb.com/
Und natürlich geht eigentlich eh nix ohne in den Code zu gucken – primär hier: https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src
Ich kann mir vorstellen einen Artikel zu nem ganz speziellen Einsatz zu schreiben.
Aber ganz allgemein ist zu umfangreich.
Vielleicht zum hier schonmal wo anders erwähnten Subtitles-Plugin?
Das ist relativ übersichtlich.
Und vielleicht guckt jemand vorbei der React so wirklich versteht und erklärt mir, wieso es doch nicht performant ist 🙂
ts meint
Hi,
ich wollte mal fragen, wie so Deine Erfahrungen mit native Blocks bzw. Components als Formular für Post Meta bzw. das Feedback dazu ist. In manchen Fällen scheint mir das eher störend, weil manche Metadaten ja u.U. gar nicht im grafischen Zusammenhang dargestellt werden sollen.
Und wie gehst Du mit Formular-Struktur-Updates um?
https://bdwm.be/gutenberg-problems-with-template_lock/
Danke =)
Sebastian Gärtner meint
Hi ts,
ich hab jetzt bei ein paar Kunden native Blöcke verwendet und deren Daten in Post_Meta schreiben lassen.
Besonders gut finde ich das eingesetzt bei sowas wie Untertitel. Also ich hatte jetzt zwei, drei Kunden wo entweder der Untertitel über dem Titel stehen sollte oder sowas wie Titel, Untertitel, Beitragsbild.
Statt ein Feld in der rechten Spalte zu machen, wo es ohne Kontext steht, gibt es ein Untertitel-Block, der via template direkt vorgegeben ist, der nur einmal verwendet werden darf, der keine grafische Ausgabe hat, aber in ein Post_Meta schreibt.
Dadurch kann ich im Template einfach das Post_Meta nutzen und die Person, die den Inhalt einpflegt, wird vermutlich nicht mal registrieren, dass da technisch was besonders dran ist.
Für komplexere Templates muss man es sich gegebenenfalls überlegen.
Finde es aber z. B. trotzdem denkbar die Single-Post-Type Ansicht mit Blöcken zu erstellen, wobei manche Blöcke sowohl Layout haben, als auch in Post_Meta schreiben.
Und bei ner Übersicht hole ich mir die Daten aus dem Post-Meta-Einträgen.
Ähnlich wie im Artikel mit ACF beschrieben.
Wobei ich, seit ich mich eingefuchst habe, wo möglich native Blöcke baue. Schneller, eleganter, leistungsstärker als ACF-Blöcke.
ts meint
Danke für die Hinweise =) Ich komm immer wieder zu diesem Beitrag zurück!
Wollte das mit den „Untertiteln“ mal für eine bestehende Seite versuchen und habe daher mal versucht, ein altes, in der REST API verfügbares ACF Custom-Field mittels Meta-Block zu aktualisieren. (Per Block Editor Handbuch…
const [ meta, setMeta ] = useEntityProp( ‚postType‘, ‚postType‘, ‚meta‘ );
const metaFieldValue = meta._legacyField;
const updateMetaValue = ( newValue ) => {
setMeta( { …meta, _legacyField: newValue } );
};
Das wäre natürlich super, wenn man so Kompatibilität zu bestehenden Daten anbieten könnte. Funktioniert nur leider (noch?) nicht.
Wenn ich den per ACF bereits definierten Feldnamen im Metablock-Plugin nochmals explizit für den PostType definiere (via register_post_meta(…) ), dann kann der native MetaBlock die Daten aus dem ACF Feld zwar lesen, aber beim Aktualisieren bekomme ich einen 403 Fehler in der REST API.
Ist das Problem bei Dir schon mal aufgetreten? Hast Du irgendeine Idee? Du meintest ja, dass Du Dich schon in die nativen Blöcke eingearbeitest hast. Ggf. hängt es auch mit der Struktur der zu aktualisierenden Daten zusammen?
cf:
https://stackoverflow.com/questions/66611930/updating-acf-via-rest-api-v3 https://stackoverflow.com/questions/53596688/update-acf-fields-inside-layout-via-wp-api
Danke =)
Sebastian Gärtner meint
Hi ts,
sieht doch erstmal nach nem guten Anfang aus.
Hast du das Meta-Feld auch abseits von ACF für die REST-API frei gegeben? Sonst ist es via REST nicht zu erreichen.
Ist das Feld auch nativ über die API verfügbar oder über ACF-Schnittstelle?
Wie sieht der Code außen drum herum aus – also das Schnipsel alleine kann ja noch nix machen.
Ich hab z. B. sowas in meinen PHP-Code:
register_meta(
'post',
'gw_publication_date',
[
'type' => 'string',
'single' => true,
'show_in_rest' => true,
]
);
und sowas
const publicationDate = useSelect(function (select) {
return select('core/editor').getEditedPostAttribute(
'meta',
)['gw_publication_date']
}, [])
const [myDate, setMyDate] = useState(publicationDate)
const {editPost} = useDispatch('core/editor')
useEffect(() => {
editPost({meta: {gw_publication_date: myDate}})
}, [myDate])
Bei mir ist so allerhand schief gelaufen 😉
Also evtl. lohnt es sich noch dran zu bleiben.
Grundsätzlich ist es auf jeden Fall möglich auch ACF-Felder via Gutenberg zu aktualisieren. ACF kocht ja auch – im Endeffekt – nur mit Meta-Fields die auch direkt beschrieben werden können.
Von den paar Code-Zeilen kann ich noch nicht erkennen, ob du nicht irgendwo einen fundamentalen Fehler hast.
Ich bin aktuell nicht mehr so komplett drinnen in Gutenberg/React/JSX, aber falls es dir das wert ist, schreib mir gerne eine Mail und wir machen eine (kostenpflichtige) Session in der wir das zum Laufen bringen.
ts meint
Hi und großes Danke für die schnelle Antwort =)
also… ich hatte das Metafeld zusätzlich zu ACF so definiert, eigentlich ja identitsch zu Deiner Definition, oder?
register_post_meta(
‚postType‘,
‚metaKey‘,
array(
’show_in_rest‘ => true,
’single‘ => true,
‚type‘ => ’string‘,
)
);
Und ich habe mal Deine Update-Funktion probiert, allerdings mit dem gleichen Resultat. Es funktioniert bei einem Metafeld, das nicht schon zuvor/auch in ACF definiert ist, aber es funktioniert nicht bei einem Feld, das schon zuvor/auch in ACF definiert ist.
Ich werde noch ein wenig weiter rätseln ;), sollte ich die Lösung finden, werde ich sie hier posten. Aber danke für das Angebot, gut zu wissen, immer gut ein Fallback zu haben, wenn das Problem mal „mission critical“ werden sollte!
Und wenn Du nicht mehr so komplett im Thema Gutenberg bist, heißt das, dass Du nicht mehr so viel mit WP in Deinen Projekten arbeitest? Frage, weil man ja immer offen für Alternativen zum Gewohnten bleiben sollte…
Sebastian Gärtner meint
Aaaah – das Problem passiert also nur, wenn ACF das Feld schon registriert hat? Hatte ich davor nicht verstanden.
Hm – magste mal deine URL teilen? Gegebenenfalls via Mail.
Ich würde mal deine REST-API Routes checken. Also wie ACF das Feld registriert und ob du eine Route für dein eigenes Feld findest.
Vielleicht überschreibt ACF da oder ist „schneller“.
Und nicht mehr so auf Gutenberg fokussiert:
Ich hab mich bei nem Unternehmen anstellen lassen, die schwerpunktmäßig Symfony einsetzen. Mein Wunsch: An einem langfristigen Projekt arbeiten und modernes PHP lernen.
Der PHP-Anteil an WordPress ist total veraltet und dadurch hab ich viele modernen PHP-Sachen noch garnicht so richtig gelernt.
Und der aktuelle Entwicklung mit Gutenberg und Full-Site-Editing stehe ich etwas skeptisch gegenüber. Für meinen Marktwert halte ich es für sehr sinnvoll nicht mehr nur auf WordPress spezialisiert zu sein. Full-Site-Editing weißt in eine Entwicklung, die für mich als Freelance-Developer nachteiligt wirkt.
ts meint
Hello again
ich denke, ich habe den Grund gefunden.
Der 403 Fehler rührte daher, dass ich als ACF Fields „protected meta“ Schlüssel verwendet hatte, als ich das mal für einen neuen Schlüssl probiert habe, trat das gleiche Problem auf. Die Lösung hier ist, eine auth-Callback Funktion in die Registrierung aufzunehmen, also z.B.
register_post_meta(
‚post_type‘,
‚_my_protected_key‘,
array(
’show_in_rest‘ => true,
’single‘ => true,
‚type‘ => ’string‘,
‚auth_callback‘ => function () {
return current_user_can( ‚edit_posts‘ );
},
)
);
Das ist offenbar selbst für Zugriffe aus dem Admin nötig.
Das ACF-Problem hatte damit direkt also nichts zu tun. Aber das Problem mit ACF-Feldern besteht trotzdem und es gibt gleich „zwei“. Zum einen schreibt ACF seine Felder in eine eigene Metahierarchie. In den Rest-Abfragen stehen sie (sofern man die nun native ACF Implementierung verwendet unter „acf:“, nicht unter „meta“. Und zum anderen ging Deine Idee mit „ACF ist schneller“ wohl in die richtige Richtung. ACF ist aber „langsamer“. Und zwar wird offenbar der Wert aus der ACF-Metabox (ob eingeblendet oder nicht) nach der Änderung des Meta-Blocks im Block-Editor erneut in das Metafeld geschrieben. Ich hab das getestet in dem ich ein Update nach jeder Eingabe gesendet habe: Wenn ich die Seite einfach irgendwann neu geladen habe, hatte der ACF-Schlüssel den richtigen Wert, aber beim Speichern über die normale WP-Aktualisieren Funktion wird immer der Wert zuletzt gespeichert, der zuletzt in der Metabox steht, egal was im MetaBlock steht.
Siehe: https://wordpress.stackexchange.com/questions/408053/update-post-meta-custom-field-using-block-editor
In dem Thread wird empfohlen, die „normalen“ Custom-Felder zu „protected“ Feldern zu machen, damit sie nicht in der Standard Custom Field UI auftauchen und beim Update überschrieben werden. Die Option besteht für ACF ja nicht, denn wenn man die ACF Felder für den post type verwenden will, werden die Metaboxen angeboten, auch wenn man sie im Editor ausblenden kann.
Das bedeutet aus meiner Sicht, dass man aktuell wohl ACF-Felder aktuell nur mittels eines Hacks im Gutenberg Editor aktualisieren kann: Man muss den entsprechenden Wert in der Metabox aktualisieren *bevor* der Block-Editor speichert, also am besten mit der Eingabe des Werts in den Metablock synchronisieren.
Danke nochmal für den Hinweis! Ich werde das weiter verfolgen und auch berichten =)
Deine Überlegungen zu WP und auch FSE kann ich gut nachvollziehen. Bin da auch noch unsicher, glaube aber immer mehr, dass FSE das System für meine Usecases eher komplexer macht (*alles* dynamische braucht ja dann einen Block). Aber ja, es stellt sich mitunter wieder öfter die Frage nach der geeigneten Plattform als in den letzten Jahren.
ts meint
kleines Update nochmal: man braucht den ACF-Schlüssel, nicht nur den eigentlichen meta-Key für den Workaround.
So funktioniert es jetzt bei mir.
const [ meta, setMeta ] = useEntityProp( ‚postType‘, ‚postType‘, ‚acf‘ );
const metaFieldValue = meta.legacyField;
const updateMetaValue = ( newValue ) => {
setMeta( { …meta, legacyField: newValue } );
document.getElementById(„acf-field_62f99453a7fa3“).setAttribute(‚value‘, newValue);
};
ts meint
Falls es jemanden interessieren sollte: in den letzten drei Episoden von „Ryan Welcher Codes“ geht es spezifisch um native Meta-Blöcke mit Daten aus ACF-Field-Groups.
https://www.twitch.tv/videos/1604490468
https://www.twitch.tv/videos/1610866187
https://www.twitch.tv/videos/1623075177