With the library group disabled the entries stay unreadable and unwritable, but page outline, node-get and render summary still name global module IDs; full hiding follows in 3b. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
41 KiB
Etappe 3 – Entscheidungen der Planung (Entwurf)
Vorbereitung von Etappe 3 („Library & Theme Builder“), 2026-09-26/27. Grundlage: Spec §3, §4.3, §5, §7, §10, §12, §15; Entscheidungen Etappe 2 (D1–D12); Rulings 2b (S1–S52), Praxistest und Security-Audit 2b. Quelle: Divi 5.2.1 (wp-content/themes/Divi, style.css:4), Pfade relativ zu themes/Divi/includes/. Live geprüft nur lesend (DDEV, wp eval-file). Entwurf – noch nicht vom Controller freigegeben. Kosten, falls falsch, jeweils am Ende.
1. Verifizierte Fakten
1.1 Divi Library (et_pb_layout)
- F1: Post-Typ
et_pb_layout(ET_BUILDER_LAYOUT_POST_TYPE,builder/post/type/Layout.php:4),capability_type post,map_meta_cap,show_ui true,show_in_rest false, unterstütztrevisions(Layout.php:79). Taxonomienlayout_category,layout_tag,layout_pack,layout_type,module_width,scope,layout_location(Layout.php:83-90). Live:assign_terms=edit_posts, verwalten =manage_categories;layout_locationist lokal nicht registriert. - F2: Anlegen (Divi 4-Weg, von Divi 5 weiter benutzt):
et_pb_submit_layout()(builder/shortcode-core.php:654-734) setzt Termescope(global/not_global),layout_type(layout/section/row/module),module_width(regular/fullwidth), Kategorien/Tags und Meta_et_pb_row_layout(Zeilen),_et_pb_module_type(Module),_et_pb_excluded_global_options = "[]"(globale Module),_et_pb_built_for_post_type,_et_pb_template_type;et_pb_create_layout()(:738-800) speichert immer mitpost_status publishüberwp_insert_post(also mit kses). Im REST-/CLI-Kontext istet_pb_submit_layoutnicht geladen (live:function_exists= false; geladen nur überbuilder/shortcode-framework.php:6). - F3: Divi 5 legt Library-Einträge über die Builder-Route
POST divi/v1/divi-library/create-iteman (builder-5/server/VisualBuilder/REST/RESTRegistration.php:743-749,DiviLibraryController::create_itemDiviLibraryController.php:606-757): D4-Konvertierung, Preset-/Farb-/Variablen-Import, dannet_pb_submit_layout(:715). Recht:edit_posts+et_pb_is_allowed('divi_library')+('save_library')(:958-966). Inhalt wird vorher mitSavingUtility::prepare_content_for_dbbereinigt (:980;VisualBuilder/Saving/SavingUtility.php:230-254: ohneunfiltered_htmlwird die Seite komplett geparst und neu serialisiert). Der Versuch, danach_et_pb_use_divi_5zu setzen, liest$new_layout_meta['layout_id']aus einem JSON-String (:715-720) – auf dieses Flag ist bei Library-Einträgen kein Verlass. - F4: Library-Einträge speichern ihren Inhalt in
post_contentin einemdivi/placeholder-Wrapper (DiviLibraryController.php:2395, 2461-2466). - F5: „Global“ = Term
scope=global; Rückfall für importierte D4-Module:_et_pb_module_typeund_et_pb_excluded_global_optionsgesetzt (builder-5/server/Packages/GlobalLayout/GlobalLayout.php:34-61,GlobalLayout::is_global_layout_template()). - F6: Instanz auf einer Seite = Platzhalterblock
divi/global-layoutmit{"globalModule":"<ID>","blockName":"divi/<typ>","localAttrs":{…}}und den Kindern alsinnerBlocks(Schnappschuss). Belegt durch die D4→D5-Konvertierung (builder-5/server/Packages/Conversion/Conversion.php:1454-1479) und die Serialisierung des Builders (builder-5/visual-builder/build/serialized-post.js, Filterdivi.serializedPost.parseFlatModuleObjectIntoBlockArray.nested: alle Attribute außerglobalModule,localAttrsMap,localChildren,globalParent,blockName,globalModuleTemplatewandern nachlocalAttrs). Kinder innerhalb einer globalen Vorlage tragenglobalParent(Conversion.php:1491-1494). Modul-Metadaten:divi/global-layouthat keine Attribute (builder-5/server/_all_modules_metadata.php:18550-18557). - F7: Ausgabe per Verweis. Beim Rendern ersetzt
BlockParserjedendivi/global-layoutdurch den aktuellen Inhalt des Library-Posts (builder-5/server/FrontEnd/BlockParser/BlockParser.php:838-884;BlockParserStore::get_global_layout_content,BlockParserStore.php:1113-1330). Aus dem SchnappschusslocalAttrswerden nur die Attribute übernommen, die die Vorlage inlocalAttrsMapals „nicht synchronisiert“ führt (apply_local_attrs_filtering,BlockParserStore.php:348); die Kinder aus der Seite nur, wenn die VorlagelocalChildren: truehat (:1307-1311). Die Seitenkopie ist also ein Schnappschuss, maßgeblich ist der Library-Post. - F8: Keine Expansion bei REST-POST.
BlockParserüberspringt die Expansion beiMigrationContext, beim Speichern und bei jedem REST-Request mit POST/PUT/PATCH (BlockParser.php:827-831,_is_rest_update_request:690-701). Unsere MCP-Aufrufe sind REST-POST –lit/page-render-summary(D5,the_contentim Prozess) sieht globale Module daher nicht. - F9: Bearbeitet man eine globale Instanz im Visual Builder, speichert der Builder sofort den Library-Post über
POST divi/v1/divi-library/save(visual-builder/build/global-layouts.js;DiviLibraryController::save:1439-1447=wp_update_post(wp_slash(…)), Inhalt vorherprepare_content_for_db). Recht:edit_posts+et_pb_is_allowed('edit_global_library')(:1494-1500) – ohneedit_postauf den Eintrag. - F10: Verschachtelte globale Module sind verboten: beim Öffnen einer globalen Vorlage im Builder werden innere
divi/global-layout„entglobalisiert“ (VisualBuilder/SettingsData/SettingsDataCallbacks.php:739-743,Framework/Portability/PortabilityPost.php:3521-3605maybe_deglobalize_nested_global_modules: Platzhalter →blockNamemitlocalAttrsals Attribute,globalParententfernt). Divi selbst liestglobalModuleaus Markup per String-Scan, weilparse_blocks()damit nicht zuverlässig umgeht (PortabilityPost.php:3510,BlockParserStore.php:1137-1184,FrontEnd/Assets/DetectFeature.php:349-359). - F11: Library-REST-Routen (
RESTRegistration.php:671-775):divi-library(Liste),/item,/update-terms,/update-item,/convert-item,/split-item,/load,/create-item,/save,/upload-image,/item-location(löscht trotz Namen Posts,DiviLibraryController.php:1197-1221). Alle nonce-geschützt, nur für den Builder. - F12: Rechte im Divi-Rollen-Editor:
et_pb_is_allowed()(builder/core.php:1128-1162); Library-Admin brauchtdivi_library+save_library(builder/functions.php:340-346), globale Einträge zusätzlichedit_global_library(functions.php:366-372; im Buildercore.php:4248-4262).theme_builderundread_dynamic_content_custom_fieldssind „gefährlich“: für andere Rollen als Administrator standardmäßig aus (core.php:1138-1156), Multisite-Super-Admins immer an. Live: keine Rollen-Einstellungen gespeichert (et_pb_role_settingsleer) → Standardwerte. - F13: Live-Bestand: 0
et_pb_layout, 0et_template, 0et_theme_builder, 0 TB-Layouts, kein Inhalt mitglobalModule(Probes1.php). Echte Library-/TB-Daten fehlen vollständig.
1.2 Theme Builder
- F14: Post-Typen
et_theme_builder,et_template,et_header_layout,et_body_layout,et_footer_layout(builder/frontend-builder/theme-builder/theme-builder.php:7-23, 89-252), allecapability_type post,show_ui false,show_in_rest false; Layouts unterstützenrevisions(:184, 216, 248), Vorlagen nicht (:152). - F15: Live- und Entwurfsstand:
et_theme_builder_get_theme_builder_post_id($live)sucht den TB-Post mit Statuspublish(live) bzw.auto-draft(Entwurf des TB-Editors), ohne Meta_et_library_theme_builder(theme-builder.php:378-413). Die Vorlagen hängen als mehrfaches Meta_et_templateam TB-Post, mit Sicherung in der Optionet_tb_templates_backup_<id>während des Speicherns (:424-441;api.php:223-243). - F16: Vorlage (
et_template) = Meta_et_default,_et_enabled,_et_autogenerated_title,_et_{header,body,footer}_layout_id,_et_{…}_layout_enabled,_et_{…}_layout_global,_et_library_item_id, mehrfach_et_use_on/_et_exclude_from(theme-builder.php:471-521).override= Layout-ID ≠ 0 oder Bereich deaktiviert (:502). - F17:
et_theme_builder_store_template($tb_id, $template, $allow_default)(theme-builder.php:1463-1586):wp_die()ohneedit_others_posts(:1464-1466); neue Vorlagen sofortpublish(:1515-1521); Layout-IDs nur übernommen, wenn der passende Typ undpublish(:1486-1496); Bedingungensanitize_text_field, dedupliziert (:1565-1583). Die Funktion hängt die Vorlage nicht an den TB-Post – das macht nuret_theme_builder_api_save(api.php:223-243). - F18:
et_theme_builder_insert_layout($options)(theme-builder.php:1643-1667):wp_die()ohneedit_others_posts,wp_insert_postmitpost_status publish(kses!), Termlayout_type=layout,et_builder_enable_for_post()(setzt_et_pb_use_builder,core.php:4438-4449). - F19: Divis TB-Speichern läuft über admin-ajax (
wp_ajax_et_theme_builder_api_save,api.php:160-273:et_builder_security_check('theme_builder', 'edit_others_posts', …)), ersetzt die gesamte_et_template-Liste des TB-Posts (:233-240), trasht beim Live-Speichern den Entwurf und markiert unreferenzierte Vorlagen/Layouts mit_et_theme_builder_marked_as_unused; nach 7 Tagen werden sie gelöscht (max. 50 je Lauf,theme-builder.php:591-678). Danachet_theme_builder_clear_wp_cache('all')undET_Core_PageResource::remove_static_resources('all','all')(api.php:249-254). - F20:
api.phpwird nur beiis_admin() || wp_doing_ajax()geladen (theme-builder.php:50-61); im REST-Kontext fehlen dieet_theme_builder_api_*-Funktionen. Vorhanden (live geprüft):et_theme_builder_insert_layout,et_theme_builder_store_template,et_theme_builder_get_theme_builder_templates,et_theme_builder_get_template_settings_options,et_theme_builder_get_flat_template_settings_options,et_theme_builder_clear_wp_cache. Divi 5 hat keine eigenen TB-REST-Routen (nurThemeBuilder/Layout.php,ThemeBuilder.phpfür die Ausgabe). - F21: Bedingungs-IDs mit Trenner
:(theme-builder.php:28):singular:post_type:<pt>:all(:703-710),archive:post_type:<pt>(nurpostoderhas_archive,:724-734),singular:post_type:<pt>:id:<id>(:805-813),singular:post_type:<pt>:children:id:<id>(:822-829),homepage(:717),search,404(:1030-1039), Archiv-, Taxonomie-, Autor-, Datumsvarianten (:873-987). Jede hat einenvalidate-Callback (template-setting-validations.php:13-325);et_theme_builder_get_flat_template_settings_options()(:1143) liefert die flache Liste. - F22: Die Layouts des Theme Builders werden bei der Ausgabe live gelesen (
et_theme_builder_get_template_layouts,theme-builder.php:1295-1406); Änderungen an einem aktiven Layout sind sofort öffentlich. Divi-Module mitappearance.themeBuilderLayouts(z. B.divi/post-content,_all_modules_metadata.php:25503;fullwidth-post-content:14455) werden in anderen Bereichen nicht gerendert (Packages/ModuleLibrary/ModuleRegistration.php:509-527). - F23: Divi-Recht für TB-Layouts im Builder:
et_pb_is_allowed('theme_builder')(functions.php:2353) plus die WP-Rechte; TB-Admin-AJAX zusätzlichedit_others_posts.
1.3 Dynamic Content, Pods, Loop
- F24:
DynamicContentOptions::get_options($post_id, $context)sammelt alles über den Filterdivi_module_dynamic_content_options(builder-5/server/Packages/Module/Layout/Components/DynamicContent/DynamicContentOptions.php:85-133). Live für Seite 831: 57 Optionen, davon 34loop_*,post_meta_key(Felderbefore|after|select_meta_key|meta_key|date_format|custom_date_format|enable_html) und je Post-Typpost_link_url_<pt>mit Feldpost_id. - F25: Meta-Schlüssel-Liste: „meistgenutzte“ Meta-Schlüssel der ganzen Website plus ACF-Felder – nur mit
read_dynamic_content_custom_fieldsoder im Kontextdisplay(DynamicContentOptionPostMetaKey.php:80-140). Pods kennt Divi nicht. - F26: Ausgabe von
custom_meta_<key>: Wert überget_post_meta/ACF, Filterdivi_module_dynamic_content_resolved_custom_meta_value(DynamicContentOptionPostMetaKey.php:404), dannesc_htmlohneenable_html(:452-457). Arrays von Strings werden mit „, “ verbunden; Beziehungs-/Dateifelder ohne ACF bleiben rohe IDs. - F27: Interner Link als natives Dynamic Content:
post_link_url_<post_type>mitsettings.post_id, Ausgabeesc_url(get_permalink($id))zur Renderzeit (DynamicContentOptionCustomPostLinkUrl.php:34, 186-217) – entwurfssicher, nach dem Veröffentlichen automatisch die schöne URL. - F28: Loop Builder:
module.advanced.loop.desktop.value.{enable, queryType, …}(Packages/Module/Options/Loop/LoopUtils.php:135-145), Werte im Loop überloop_*-Optionen; die Expansion läuft nur beim Rendern (BlockParser.php:895-905).
1.4 Stand im Plugin
- F29:
ContentSchema::EXCLUDEDschließtet_pb_layout,et_theme_builder,et_templateund die drei TB-Layout-Typen aus (src/Integrations/WordPress/Schema/ContentSchema.php:19-24);PostGuard::editableliefert dafürnot_found. Die Divi-Werkzeuge erreichen Library und TB heute nicht. - F30: Opak sind Blöcke mit
globalModule,divi/global-layoutoder nicht dekodierbaren Attributen (src/Integrations/Divi/BlockTree/Parser.php:56);Block::setAttrswirft dort (Block.php:91-96). - F31: Parser-Kosten (live, 8 Divi-Posts, 28 KB, 20 Durchläufe): Parse + NodeIndex ≈ 2 ms je 100 KB Inhalt (Probe
s3.php). - F32: Divi 5.2.1 registriert keine WordPress Abilities (
grep wp_register_ability|wp_abilities_api_initim Theme: 0 Treffer) und enthält kein MCP.
2. Empfohlene Entscheidungen
- E1 – Ein Zugang für alle Divi-Posts. Die bestehenden Divi-Werkzeuge (
lit/divi-outline,-node-get,-insert,-update,-move,-delete,-duplicate-node) akzeptieren zusätzlich IDs vonet_pb_layoutundet_header/body/footer_layout(Spec §5.1). Umsetzung: eineDiviTarget-Richtlinie nebenPostGuard(Typ, Recht, Status-Regel je Typ), dieDiviPageLoaderverwendet;ContentSchema::EXCLUDEDbleibt (die Content-Tools sehen diese Typen weiter nicht). – Grund: keine zweite Werkzeugfamilie, gleiche Pipeline (D7, S39). – Kosten, falls falsch: Rechteprüfung pro Typ an einer Stelle falsch → Zugriff auf Library/TB ohne Divi-Recht; abgefangen durch eigene Tests je Typ. - E2 – Globale Module werden im Library-Post bearbeitet, nie in der Seitenkopie. Auf Seiten bleiben
divi/global-layout-Knoten opak (D3);lit/divi-node-get/-outlineliefern für sieglobal_id,block_nameund einen Hinweis „mit post_id=<global_id> bearbeiten“ (S19-Teil 2). Schreiben in den Library-Post wirkt auf alle Instanzen (F7); die Antwort nennt die betroffenen Seiten (Verwendungssuche über"globalModule":"<id>"inpost_content, wie Divi F10) und verlangt bei mehr als einer veröffentlichten Instanzconfirm: true.localAttrs/Kinder-Schnappschüsse in Seiten werden nie angefasst; das Bearbeiten nicht synchronisierter Attribute einer einzelnen Instanz ist nicht Teil von Etappe 3. – Grund: Divis Ausgabe ist per Verweis (F7), der Builder macht es genauso (F9). – Kosten: Instanz-spezifische Abweichungen nur im Builder. - E3 – Rechte (strenger als Divi, nie lockerer). Library lesen:
edit_posts+divi_library; speichern/anlegen: +save_library; einfügen aus der Library: +add_library; globalen Eintrag bearbeiten: +edit_global_libraryundedit_postauf den Eintrag (Divi prüft das nicht, F9). Theme Builder lesen und schreiben:edit_others_posts+et_pb_is_allowed('theme_builder')(F19, F23; Spec §4.5 um die Divi-Rolle ergänzt). Dynamic-Content-Meta-Liste nur mitread_dynamic_content_custom_fields(F25). Weilet_theme_builder_store_template/insert_layoutbei fehlendem Rechtwp_die()aufrufen (F17, F18), prüft das Plugin vorher selbst.et_pb_is_allowedsteckt in einem Adapter (E15). – Kosten: ein Redakteur mit WP-Rechten, aber ohne Divi-Rolle, bekommtforbidden(gewollt, wie im Builder). - E4 – Library-Einträge legt das Plugin selbst an (kein
et_pb_submit_layout, keine Builder-Route):wp_insert_postmit leerem Inhalt und Statuspublish(Divi kennt keine Library-Entwürfe, F2), Terme/Meta wie F2, danach Inhalt überDiviSaver::saveNewim kses-Fenster (D7, D11-Nachtrag), eingewickelt indivi/placeholder(F4), Flags wieDiviFlags. Ist ein Schritt fehlerhaft, wird der Entwurf endgültig gelöscht (wielit/content-create). – Grund:et_pb_submit_layoutist im REST-Kontext nicht geladen und speichert mit kses (F2); die Builder-Route braucht Nonce und importiert Presets/Farben (F3). – Kosten: Divi ändert Terme/Meta → Einträge fehlen in der Library-Ansicht; abgesichert durch Fixture-Vergleich mit echten Builder-Einträgen (E13) und Kompatibilitätsprüfung (E15). - E5 –
lit/library-insertals Kopie oder globale Instanz. Kopie: Inhalt ohnedivi/placeholder, verschachtelte globale Platzhalter entglobalisiert wie Divi (F10), eingefügt wielit/divi-insert(StructureRules, AdminLabel). Globale Instanz: das Plugin erzeugt<!-- wp:divi/global-layout {"globalModule":"<id>","blockName":"<Wurzeltyp>"} --><!-- /wp:divi/global-layout -->ohnelocalAttrs(voll synchronisiert). Prüfungen: Eintrag existiert,publish,scope=global,read_post, Wurzeltyp passt an die Zielposition, kein globales Modul in einem globalen Library-Post (F10). – Kosten: falls der Builder leerelocalAttrs/fehlendeinnerBlocksanders erwartet, sieht der Mensch im Builder evtl. eine andere Darstellung – vor dem Bau mit einer Builder-Fixture verifizieren (E13). - E6 – Werte aus gespeicherten Inhalten (Library → Seite, Seite → Seite, Seite → Library) gelten als „gespeichert, nicht vom Client“ wie bei
lit/divi-duplicate-node, werden aber beim Wechsel des Posts erneut geprüft: für Benutzer ohneunfiltered_htmlwerden Knoten mit Builder-only-Feldern (S7/S26:*.decoration.attributes,*.advanced.html,*.css.*) und Code-Modul abgelehnt („nur im Divi-Builder“). Alles andere geht unverändert durch den BlockTree (byte-identisch). – Grund: Audit M1 – der Weg über eine andere Post-ID darf die Builder-only-Sperre nicht umgehen; Autor und damit Divisbefore/after-Filterung ändern sich mit dem Ziel-Post (R2-Befund 1). – Kosten: Redakteure können admin-gebaute Abschnitte mit eigenem CSS nicht kopieren. - E7 – Theme Builder: Vorlagen und Layouts über Divis vorhandene Funktionen (
et_theme_builder_insert_layoutmit leerem Inhalt, Inhalt danach überDiviSaver::saveNew;et_theme_builder_store_template), Zuordnung zum Live-TB-Post selbst (add_post_meta($live_id, '_et_template', …), gleiche Reihenfolge wie F19 inkl. Backup-Option), danach Cache wie F19. Nie der Entwurfs-TB-Post, nieet_theme_builder_trash_draft_and_unused_posts(). Existiert ein TB-Entwurf (auto-draft, F15), wird abgelehnt mit Hinweis „Theme Builder ist in Bearbeitung – dort speichern oder verwerfen“ (sonst überschreibt ein späteres Speichern im TB-Editor die Zuordnung und die neue Vorlage wird nach 7 Tagen gelöscht, F19). Bedingungen nur auset_theme_builder_get_flat_template_settings_options()plus derenvalidate-Callback, Post-IDs mitread_post. – Kosten: Divi ändert die TB-Speicherung → Vorlage fehlt im TB-Editor; Kompatibilitätsprüfung + E2E. - E8 – Neue TB-Vorlagen werden deaktiviert angelegt (
_et_enabled=0); aktivieren ist eine explizite Aktion inlit/tb-assign(enabled: true,confirm: true, Liste der betroffenen Bedingungen). Standardvorlage (_et_default) nie über MCP. – Grund: Spec §2 Prinzip 5 (Status bleibt, Veröffentlichen explizit); TB-Posts kennen keinen Entwurf (F17, F18, F22). – Kosten: ein Aufruf mehr. Offen als Frage F-1. - E9 – Werkzeugliste Etappe 3 und Exposition. Direkt: nur
lit/library-insert(Spec §4.3) → 22 direkte Tools, unter der Warnschwelle 25 des Tools-Tabs. Indirekt:lit/library-list(mitid→ Detail; ersetztlit/library-get),lit/library-save,lit/divi-node-copy,lit/library-make-global,lit/library-find-similar,lit/divi-dynamic-sources,lit/tb-list,lit/tb-create-template,lit/tb-assign. Gruppen: Library und Theme Builder als eigene Gruppen („nur lesen“ wirkt wie bei Divi, Audit M2:lit/library-insertundlit/divi-node-copyfolgen zusätzlich dem Modus vonlit/divi-insert). Destruktiv-Hinweis:lit/library-make-global(ersetzt Knoten),lit/tb-assign(öffentliche Wirkung). – Kosten:lit/library-getaus der Spec entfällt als eigener Name (Spec §5.7 anpassen). - E10 –
lit/library-make-global: legt einen globalen Eintrag aus dem Knoten an (E4) und ersetzt den Knoten durch eine Instanz (E5), in einem Aufruf, alles oder nichts (Library-Post wird bei Fehlschlag der Seite gelöscht). „Gleichartige Vorkommen ersetzen“ nur für inhaltsgleiche Knoten (Inhalts-Fingerabdruck, E11), mit Probelauf (Standard) undconfirm: trueje Seite mittree_rev(Muster D10). Strukturgleiche Knoten mit anderen Texten werden nur gemeldet, nie ersetzt (Spec §3.3 „fast gleich“ = später). – Kosten: Kunde muss ähnliche Abschnitte vorher angleichen. - E11 –
lit/library-find-similar: zwei Fingerabdrücke je Abschnitt/Zeile: Struktur (Blocknamen und Tiefe, Spalten-flexType, Preset-IDs) und Inhalt (kanonische Attribute ohne Admin-Label, Bytes der Kinder). Suche seitenweise mitcursor, Post-Typ-Filter, höchstens 200 Posts je Aufruf, nur Posts, die der Benutzer bearbeiten darf; kein Index/Meta (F31: ≈1 s Parse für 1000 Seiten à 50 KB, Datenbanklast dominiert). Die Schreibwarnung „ähnliche Abschnitte“ (Spec §5.5, D6) vergleicht nur mit Library-Einträgen (klein) und verweist sonst auf das Tool. – Kosten: auf sehr großen Websites mehrere Aufrufe; bei Bedarf später ein Cache nachtree_rev. - E12 – Dynamic Content.
lit/divi-dynamic-sources(post_type)liefertDynamicContentOptions::get_optionsfür einen Beispiel-Post des Typs (sonst0), ohneloop_*(S36), dazu Pods-Felder des Typs ausPodsFieldSourcemit Speicherart und Eignung (Text-ähnlich ={{field:<name>}}; Beziehung/Datei = „zeigt IDs“, F26). Beim Schreiben in einen TB-Body-Layout gilt als Kontext-Post-Typ der Typ aus den Bedingungen der zugeordneten Vorlage (singular:post_type:<pt>:…); ohne Zuordnung Warnung. Loop Builder bleibt lesbar/opak (Werte unverändert), wird nicht erzeugt. – Kosten: CPT-Archive mit Pods-Feldern in Schleifen erst später. - E13 – Übernahmen aus Etappe 2: (a)
{{link:<post_id>}}→post_link_url_<post_type>mitsettings.post_id(F27), Prüfungread_post, kein Papierkorb; nur in URL-Feldern; (b)lit/guidemittopic: "all"(alle Themen in einem Aufruf, Größenlimit); (c) S19:lit/divi-design-systemmit Filter (section: colors/variables/presets/fonts,modulefür Presets) undglobal_idinnode-get; (d)lit/page-render-summarymeldet globale Platzhalter als Hinweis „globales Modul – im Auszug nicht enthalten“ (F8) und erhält für Library-/TB-IDs keinen Zugang. – Kosten: gering. - E14 – Reihenfolge und Aufteilung. 3a „Library“: Fixtures (E16) → Übernahmen E13 →
DiviTarget/Rechte (E1, E3) →lit/library-list→ Divi-Werkzeuge auf Library-Posts inkl. globaler (E2) →lit/library-save(E4) →lit/library-insert(E5) →lit/divi-node-copy(E6) →lit/divi-dynamic-sources(E12) → Guides/Promptglobale-module-vorschlagen. 3b „Theme Builder & Konsolidierung“:lit/tb-list→ TB-Layouts in den Divi-Werkzeugen (inkl.themeBuilderLayouts-Regel F22 in StructureRules) →lit/tb-create-template(E7, E8) →lit/tb-assign→lit/library-find-similar+ Warnung (E11) →lit/library-make-global(E10) → Guidetheme-builder, Promptcustom-post-type-vorlage. Abschluss jeder Teiletappe wie 2b (Review je Task, Security-Audit, Praxistest). – Kosten: find-similar/make-global kommen spät; sie hängen an stabilen Library-Grundlagen. - E15 – Divi-Zugriffe über Adapter mit Live-Kompatibilitätsprüfung (siehe Abschnitt 5): je Divi-Bereich eine Klasse (
DiviModulesundDesignSystemReadergibt es schon; neuDiviLibraryStore,DiviThemeBuilder,DiviRoles), die Funktions-/Klassen-Existenz und Signaturen prüft und bei Abweichungunsupportedstatt Fatal liefert;lit/site-statuszeigt den Befund. – Kosten: etwas mehr Code; spart Ausfälle nach Divi-Updates. - E16 – Teststrategie. (1) Unit: Platzhalter-Erkennung, Fingerabdrücke, Bedingungs-Validierung, Instanz-Markup, Entglobalisieren gegen Divis
maybe_deglobalize_nested_global_modules(gleiche Eingaben, gleiches Ergebnis). (2) Fixtures aus echten Builder-Daten: Jan-Niclas baut vor Beginn in DDEV im Visual Builder nach Checkliste globales Modul, globale Zeile mit einem nicht synchronisierten Attribut, globaler Abschnitt, normaler Library-Abschnitt, je eine Seite mit Instanzen, eine TB-Vorlage „Person“ mit Header/Body/Footer und Bedingungen; ein neues Lese-Skripttests/Integration/divi-export-library.phpexportiertpost_content, Terme, Meta und TB-Meta alsbuilder-library-*.html/builder-tb-*.json(wie D12). Roundtrip-Test läuft automatisch mit. (3) DDEV-Smokedivi-library-smoke.sh/tb-smoke.sh(mit Aufräumen). (4) Manuelle Abnahme: vom Plugin erzeugte Einträge/Instanzen/Vorlagen im Builder und TB-Editor öffnen und speichern. – Kosten: ohne Fixtures (F13) bleiben E4/E5/E7 Vermutung; daher Fixtures als erster Schritt und Bedingung für den Bau. - E17 – Sicherheit neuer Schreibwege: jeder Weg nach
post_contentvon Library- und TB-Posts geht durch Composer/AttrWriter/TreeEditor →DiviSaver(D7, S39); Titel, Terme und Meta über WordPress mit üblicher Filterung (sanitize_text_field,wp_set_object_termsmit bestehenden Term-IDs; neue Terme nur mitmanage_categories); keine Builder-Route und keinet_pb_create_layoutmit Client-Inhalt; TB-Bedingungen nur aus Divis Liste; Revision vor jeder Änderung (Library und TB-Layouts unterstützen Revisionen, F1/F14), Protokolleintrag je Post; nach Library-/TB-Änderungenremove_static_resources('all','all',true)undet_theme_builder_clear_wp_cache('all')(Spec §5.6 Schritt 5). – Kosten: Review-Pflicht wie D7.
3. Fragen an den Benutzer (nach Wichtigkeit)
- Sollen neue Theme-Builder-Vorlagen sofort wirken? Divi kennt für Vorlagen keinen Entwurf.
- (a) Deaktiviert anlegen, Aktivieren nur ausdrücklich mit
lit/tb-assignund Bestätigung. Empfehlung. - (b) Sofort aktiv, wie im TB-Editor.
- (c) Aktiv nur auf Bedingungen für einzelne IDs, alles Breitere (ganzer Post-Typ, Archiv) deaktiviert.
- (a) Deaktiviert anlegen, Aktivieren nur ausdrücklich mit
- Wie frei darf der KI-Assistent globale Module ändern? Jede Änderung wirkt sofort auf allen Seiten, auch veröffentlichten.
- (a) Erlaubt mit Rechten wie im Builder,
confirm: trueund Liste der betroffenen Seiten. Empfehlung. - (b) Nur Administratoren (
unfiltered_html/manage_options). - (c) Globale Einträge nur lesen, Änderungen nur im Builder.
- (a) Erlaubt mit Rechten wie im Builder,
- Was zuerst: Library oder Theme Builder?
- (a) 3a Library (globale Module, Einfügen, Kopieren), dann 3b Theme Builder. Empfehlung (technisch sauberere Grundlage).
- (b) Theme Builder zuerst, weil ein Kunde CPT-Vorlagen braucht (Library-Teil danach).
- Pods-Beziehungs- und Dateifelder im Theme Builder: Divi zeigt davon nur IDs.
- (a) In Etappe 3 nur Text-ähnliche Pods-Felder anbieten, andere als „nicht geeignet“ melden. Empfehlung.
- (b) Das Plugin formatiert Pods-Werte beim Rendern (Filter
divi_module_dynamic_content_resolved_custom_meta_value) – wirkt dann auf der Website, auch ohne MCP. - (c) Ganz auf später verschieben.
- Woher kommen die echten Fixtures?
- (a) Du baust sie lokal in DDEV nach Checkliste, ein Skript exportiert sie. Empfehlung.
- (b) Export von einer Kundenseite (anonymisiert).
- (c) Nur aus Divi-Code abgeleitet (riskant, F13).
4. Risiken
| Risiko | Gegenmaßnahme |
|---|---|
Keine echten Library-/TB-Daten lokal (F13); Instanz-Format (localAttrs, innerBlocks, globalModule an der Vorlagenwurzel) nur aus Code/minifiziertem JS abgeleitet |
Fixtures zuerst (E16, Frage 5), Builder-Abnahme |
Späteres Speichern im TB-Editor überschreibt unsere _et_template-Zuordnung, Vorlage wird nach 7 Tagen gelöscht (F19) |
Ablehnung bei TB-Entwurf (E7), lit/tb-list zeigt unzugeordnete Vorlagen |
| Globale Änderung wirkt sofort auf veröffentlichte Seiten | confirm, Seitenliste, Revision des Library-Posts (E2, Frage 2) |
page-render-summary sieht globale Module nicht (F8) |
Hinweis im Auszug (E13d) |
et_theme_builder_* rufen wp_die() statt Fehler zu liefern (F17, F18) |
Vorabprüfung der Rechte, Adapter (E3, E15) |
| Divi-Interna ändern sich (Library-Meta, TB-Meta, Instanz-Format); ET kündigt ein offizielles MCP an | Adapter + Kompatibilitätsprüfung (E15), Fixture-Tests je Divi-Update |
| Builder-only-Werte gelangen über Kopie in fremde Posts (Audit M1-Muster) | E6 |
Pods mit Tabellen-Speicherung: get_post_meta findet nichts |
lit/divi-dynamic-sources meldet solche Felder als ungeeignet (E12) |
| Rollen-Editor: „gefährliche“ Divi-Rechte standardmäßig nur für Administratoren | E3, klare forbidden-Meldung mit Hinweis auf Divi → Rollen-Editor |
Große Websites: find-similar lädt viel post_content |
Cursor, 200 Posts je Aufruf (E11) |
| Loop Builder / Archive nicht abgedeckt | bewusst später (E12) |
5. Schnittstellen-Einordnung
Stufen: (a) öffentliche/dokumentierte API (WordPress-Kern, dokumentierte Divi-Hooks), (b) Divis Builder-REST/AJAX (divi/v1, admin-ajax, nonce-geschützt), (c) interne PHP-Klassen/Funktionen/Meta-Konventionen, (d) selbst nachgebildete interne Formate. Empfehlung: B = behalten, W = wechseln auf offizielleren Weg, A = in Adapter mit Live-Kompatibilitätsprüfung (E15).
Zur Offizialität: Elegant Themes dokumentiert Hooks und die Modul-API (dev.elegantthemes.com, u. a. divi_module_dynamic_content_options, divi_module_dynamic_content_resolved_custom_meta_value, divi_module_dynamic_content_custom_meta_options, divi_module_library_register_module_attrs), aber keine API für externen oder KI-Zugriff. Der Divi AI Agent läuft im Builder (im Browser, AI-Wallet-Abrechnung); in den Kommentaren zur Ankündigung schreibt ET, ein „official MCP is on the way“. Divi registriert keine WordPress Abilities (F32).
5.1 Bereits genutzt (Etappe 2a/2b)
| Schnittstelle | Stelle im Plugin | Stufe | Risiko bei Divi-Updates | Empfehlung |
|---|---|---|---|---|
WordPress-Kern: wp_update_post, Revisionen, kses an/aus, Meta-API |
DiviSaver, RevisionPoint |
a | gering | B |
Block-Delimiter-Format (<!-- wp:… -->, WP_Block_Parser-Muster) |
BlockTree/Parser |
a (WP-Format) | gering | B |
Divi-Blocknamen und Attribut-JSON (module.decoration…, flexType, divi/placeholder) |
Composer, AttrWriter, ColumnWidths |
d (Schema aus c) | mittel | B – Pfade werden gegen den Live-Katalog validiert; Builder-Fixtures |
ModuleRegistration::get_all_core_modules_metadata(), get_default_attrs() |
Schema/DiviModules |
c | mittel | A (Adapter existiert; Prüfung in lit/site-status ergänzen) |
GlobalData::get_global_colors/-variables, GlobalPreset::get_data, Option et_divi |
Design/DesignSystemReader, MediaUsageFinder |
c (REST-Pendant divi/v1/global-data/* = b) |
mittel | A; kein Wechsel auf b (nonce, Builder-Kontext) |
DynamicContentOptions::get_options() |
Pages/DynamicContentMap |
c; Füllweg über dokumentierten Filter divi_module_dynamic_content_options (a); REST divi/v1/dynamic-content/options (b) |
mittel | A (Rückfall auf Standard-Map existiert) |
$variable(...)$-Syntax, gcid/gvid, Dynamic-Content-JSON |
Compose/VariableRef, Placeholders |
d | mittel | B + Prüfung gegen Divis Regex ET_THEME_BUILDER_DYNAMIC_CONTENT_REGEX_D5 (theme-builder.php:36) im Kompatibilitätstest |
Meta _et_pb_use_divi_5, _et_pb_use_builder, _et_pb_show_page_creation |
Pages/DiviFlags, PostPresenter |
d (nachgebildet aus SyncToServerController) |
mittel | B; _et_pb_use_builder könnte über et_builder_enable_for_post() (c) laufen – kein Gewinn |
ET_Core_PageResource::remove_static_resources() |
DiviSaver |
c (dokumentierter Hook et_core_page_resource_post_id_before_clear deutet auf stabile API) |
gering | B |
et_builder_enabled_for_post_type() |
ContentSchema |
c | gering | B |
ET_BUILDER_PRODUCT_VERSION |
DiviModules |
c | gering | B |
Divis wp_insert_post_data-Filter (AttributeSecurity, HtmlSecurity) als Verteidigung in der Tiefe |
Verhalten, kein Aufruf | c | mittel | B (nie entfernen, S7) |
5.2 Geplant (Etappe 3)
| Schnittstelle | Zweck | Stufe | Risiko | Empfehlung |
|---|---|---|---|---|
| Post-Typen, Taxonomien, Meta der Library (F1, F2) | Liste, Anlegen (E4) | c/d | mittel | A (DiviLibraryStore), Vergleich mit Builder-Fixtures |
GlobalLayout::is_global_layout_template() |
„global?“ | c | gering | B (Divis eigene Definition statt Term-Logik) |
divi/global-layout-Platzhalter (globalModule, blockName, localAttrs) |
Instanzen (E5, E10) | d | hoch | A + Fixtures; nur minimale Form ohne localAttrs erzeugen |
Entglobalisieren wie PortabilityPost::maybe_deglobalize_nested_global_modules |
Kopie einfügen (E5) | c | mittel | Eigene Umsetzung (d), per Test gegen Divis Methode geprüft (Aufruf direkt wäre möglich, arbeitet aber auf Strings ohne unsere Byte-Garantie) |
Builder-Routen divi/v1/divi-library/* (F11) |
– | b | mittel | nicht nutzen: Nonce, fehlende Pro-Eintrag-Rechte (F9), create-item hängt an nicht geladenem Code (F2, F3) |
et_pb_is_allowed() |
Divi-Rollen (E3) | c | gering | A (DiviRoles) |
et_theme_builder_insert_layout, et_theme_builder_store_template |
TB schreiben (E7) | c (in Spec genannt) | mittel | B über Adapter DiviThemeBuilder, Rechte vorab (wp_die) |
et_theme_builder_get_theme_builder_post_id, …_get_theme_builder_templates, …_get_template |
TB lesen | c | gering | B/A |
_et_template-Zuordnung + Backup-Option (F15, F19) |
Vorlage aktivieren | d (admin-ajax-Weg et_theme_builder_api_save = b, im REST-Kontext nicht geladen) |
mittel | A; bei Divi-Update prüfen, ob et_theme_builder_api_save die Logik ändert |
et_theme_builder_get_flat_template_settings_options() + validate-Callbacks |
Bedingungen (E7) | c | gering | B |
et_theme_builder_clear_wp_cache, remove_static_resources('all','all',true) |
Cache | c | gering | B |
DynamicContentOptions::get_options() je Post-Typ |
lit/divi-dynamic-sources |
c (Filter a) | mittel | A (vorhandener DynamicContentMap) |
post_link_url_<pt> + post_id |
{{link:ID}} (E13a) |
d (Format), Registry c | gering | B – Name über die Registry prüfen, nicht fest verdrahten |
divi_module_dynamic_content_resolved_custom_meta_value |
nur falls Frage 4 = (b) | a | gering | B (dokumentiert) |
appearance.themeBuilderLayouts aus den Modul-Metadaten |
StructureRules für TB-Bereiche | c | gering | B (aus Live-Katalog) |
Loop Builder (module.advanced.loop) |
– | d | hoch | nicht erzeugen (E12) |
| WordPress Abilities von Divi | – | – | – | gibt es nicht (F32); beobachten, ob ETs angekündigtes MCP eine offizielle Schnittstelle bringt, die c/d-Teile ersetzen kann |
Quellen der Web-Recherche: Divi AI Agent – Ankündigung, Divi Dev Docs – Filter, Divi Developers.
5. Antworten des Benutzers (2026-09-27)
- F1 Theme-Builder-Vorlagen: standardmäßig deaktiviert angelegt; Aktivieren über ein eigenes Tool (explizit).
- F2 Globale Module bearbeiten: erlaubt mit Trockenlauf (Liste der betroffenen Seiten) und
confirm, vorher Revision/Sicherung des Bibliothekseintrags. - F3 Reihenfolge: erst 3a Bibliothek, dann 3b Theme Builder.
- F4 Pods-Beziehungs-/Dateifelder: als dynamische Quelle nur textartige Felder anbieten; andere mit Hinweis auslassen.
- F5 Testdaten: selbst erzeugen („Probier es selbst“) – über Divis eigene Speicherwege (Builder-REST-Controller/Services im Prozess), als „[Fixture] …“ markiert, danach als Fixtures ins Plugin exportiert. Pods ist lokal deaktiviert; Aktivierung für 3b beim Benutzer anfragen.
6. Umsetzung Etappe 3a (Plan 2026-09-27-etappe-3a-bibliothek.md)
- E5 präzisiert durch die Builder-Fixtures: Instanzen werden wie im Visual Builder erzeugt –
localAttrs= vollständiger Schnappschuss der Wurzel-Attribute (oberste Schlüssel sortiert), Kinder mitglobalParent, ohne Kinder selbstschließend – statt der minimalen Form ohnelocalAttrs. Byte-Test gegenpage--globale-instanzen.html. - Neuer Befund 9: Bibliothekseinträge aus Divis Dialog haben
\r\nzwischen Blöcken (Formular-Upload);LibraryContent::load()vereinheitlicht das vor jeder Übernahme (undurchsichtige Blöcke bleiben unberührt). - Kopie eines normalen Eintrags mit globalen Instanzen: Instanzen bleiben verknüpft (wie Divis
/load); entglobalisiert wird nur der Inhalt globaler Einträge (Divis Schadensbegrenzung, F10).lit/library-savemitscope: "normal"übernimmt enthaltene Instanzen ebenfalls als Verweise.mode: "global"nur für globale Einträge mit genau einer Wurzel ohne globale Module (P11: nie verschachtelte Instanzen). - E6 erweitert:
StoredNodeGuardprüft neben den S7/S26-Pfaden und dem Code-Modul auch fremde Blöcke, Freitext, nicht lesbare Blöcke, kses-instabilen Rich-Text (P3) und$variable-Verweise (Ablehnung, wenncanonical()sie für das Ziel ablehnt oder ihre Einstellungen verändern würde) – Grund: R2-Befund 1 (before/after nach dem Autor des Ziel-Posts). Lesbare globale Instanzen werden geprüft (localAttrs und Schnappschuss), nicht abgelehnt (P15). Strenger als Divi; sichtbare Ablehnung. URL-Werte:url($v) === trim($v)oder relativer Link ohne Schema (P17/P18) –kontakt/,/pfad,#ankerbleiben kopierbar. - Builder-only erweitert (S7-Gate, gilt auch für Seiten):
decoration.interactions(P16 – der Effekt „Attribut“ setzt im Browser beliebige Attribute, z. B.onclick; „Cookie“ setzt Cookies) undlottie.innerContent(P19 –srclädt fremdes JSON, lottie-web wertet Ausdrücke aus). Offen für Etappe 4: Divi-Presets können beides tragen; Preset-Schreibwege brauchen dasselbe Gate. - E3 ergänzt: neue Einträge zusätzlich nur mit
publish_posts(Bibliothekseinträge sind immerpublish);scope: "global"braucht zusätzlichedit_global_library(P7). Ohne das Divi-Recht „Divi-Bibliothek“ (oder mit deaktivierter Gruppe, P9) ist jede Bibliotheks-IDnot_found, byte-gleich mit einer fehlenden ID (P12); ohneedit_postauf dem Eintragforbiddenohne Titel.lit/library-listlistet nur Einträge mitedit_postund liest höchstens 500 Zeilen je Aufruf. - E9 umgesetzt mit:
lit/divi-node-copyundlit/divi-dynamic-sourcesin der Gruppe „Divi“; die Gruppe „Divi-Bibliothek“ sperrt als Ganzes („nur lesen“/deaktiviert) auch Schreibzugriffe der Divi-Werkzeuge auf Bibliothekseinträge (ExposurePolicy::groupWritable).lit-library-insertundlit/divi-node-copyfolgen zusätzlich dem Zustand vonlit/divi-insert(M2). P13 in 3a nur dokumentiert (Guide „Rechte“, Grenze): bei deaktivierter Gruppe oder ohnedivi_librarynennen Outline/node-get/Render-Auszug einer Seite noch die ID globaler Module; der Eintrag selbst bleibtnot_found. Vollständiges Ausblenden folgt in 3b. - Antwort F2: jede Änderung eines globalen Eintrags ist zuerst ein Probelauf (auch ohne veröffentlichte
Instanzen);
lit-divi-deletenutzt dasselbeconfirm, seinconfirm_requirednennt dann ebenfalls die betroffenen Seiten. P8a: die Bestätigung wird abgelehnt, wenn der Benutzer einen Eintrag mit Statuspublish,privateoderfuture, der den Eintrag zeigt, nicht bearbeiten darf (auch TB-Layouts und andere Bibliothekseinträge); Entwürfe blockieren nicht. Der Probelauf nennt solche IDs vorab inblocked_ids(P14). Revisionen aus: abgelehnt ohneunfiltered_html(die Sicherung liefe durch kses) oder bei deaktiviertem Papierkorb (P9); scheitert das Speichern nach einer Sicherung, nennt der Fehlerbackup_id(P14). Cache-Leerung für alle Seiten und den Theme Builder. - P1:
lit/divi-replace-textspeichert normale Bibliothekseinträge überDiviWriter::commit(); globale nie (die Ziele tragen keinconfirm) – das Ergebnis nennt die betroffenen Seiten und verweist auflit-divi-updatemitconfirm. - Bibliothekseinträge bekommen keine Divi-Flags (Befund 4);
_et_pb_row_layoutwird nicht geschrieben (Befund 5). - E13a:
{{link:<ID>}}nur in URL-Feldern; Ziel muss existieren,read_postbestehen, nicht Papierkorb,auto-draftoderinheritsein – Anhänge sind damit ausgeschlossen (P10). Entwürfe und private Ziele rendert Divi für Besucher als?page_id=<ID>(nur die ID wird sichtbar, Preflight). - F4/E12:
lit/divi-dynamic-sourceslistet nur textartige Felder; Beziehungs-/Dateifelder („nur IDs“), Tabellen-Speicher und unbekannte Feldtypen (P9) stehen unteromitted; Auswahlfelder zeigen den gespeicherten Wert, nicht die Beschriftung. Der Beispiel-Post ist nur einer, den der Benutzer bearbeiten darf. - E15: Adapter
DiviRoles,DiviLibraryStore, PrüfungDiviCompatibilityinlit-site-status(problemsje Komponente). - E13d umgesetzt als Hinweis in
notes; eine eigene Expansion globaler Module im Auszug unterbleibt. - Tests: die Unit-Suite läuft mit
memory_limit512M (phpunit.xml.distundcomposer test), weil der Divi-Katalog beim Standard von 128M nicht mehr in den Speicher passt. - Server-Instructions: Zeile „Divi-Bibliothek: …“ nur bei aktiver, beschreibbarer Gruppe; MCP-Prompts gibt es
noch nicht, der Ablauf „globale Module vorschlagen“ steht im Guide
divi-library(E14).