Files
WP-LIT-MCP/docs/superpowers/notes/2026-09-27-etappe-3-entscheidungen-entwurf.md
T
janniclas.loosenandClaude Opus 5.5 7590da4d96 fix: layout-edit dry runs name only editable live templates (ruling Q22)
ThemeBuilderEdits::showing() splits the live templates that show a layout
into editable ones (named under templates) and a hidden_templates count;
confirm is still decided on all of them, so a layout shown only by
uneditable templates still needs confirm. The live split is read once per
write for the confirm check and the field warnings, and field warnings now
also survive a non-confirm refusal such as the P9 backup refusal (M-12 a).
replace-text passes hidden_templates on; the write schema lists it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
2026-09-27 22:57:45 +02:00

45 KiB
Raw Blame History

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ützt revisions (Layout.php:79). Taxonomien layout_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_location ist lokal nicht registriert.
  • F2: Anlegen (Divi 4-Weg, von Divi 5 weiter benutzt): et_pb_submit_layout() (builder/shortcode-core.php:654-734) setzt Terme scope (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 mit post_status publish über wp_insert_post (also mit kses). Im REST-/CLI-Kontext ist et_pb_submit_layout nicht geladen (live: function_exists = false; geladen nur über builder/shortcode-framework.php:6).
  • F3: Divi 5 legt Library-Einträge über die Builder-Route POST divi/v1/divi-library/create-item an (builder-5/server/VisualBuilder/REST/RESTRegistration.php:743-749, DiviLibraryController::create_item DiviLibraryController.php:606-757): D4-Konvertierung, Preset-/Farb-/Variablen-Import, dann et_pb_submit_layout (:715). Recht: edit_posts + et_pb_is_allowed('divi_library') + ('save_library') (:958-966). Inhalt wird vorher mit SavingUtility::prepare_content_for_db bereinigt (:980; VisualBuilder/Saving/SavingUtility.php:230-254: ohne unfiltered_html wird die Seite komplett geparst und neu serialisiert). Der Versuch, danach _et_pb_use_divi_5 zu 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_content in einem divi/placeholder-Wrapper (DiviLibraryController.php:2395, 2461-2466).
  • F5: „Global“ = Term scope=global; Rückfall für importierte D4-Module: _et_pb_module_type und _et_pb_excluded_global_options gesetzt (builder-5/server/Packages/GlobalLayout/GlobalLayout.php:34-61, GlobalLayout::is_global_layout_template()).
  • F6: Instanz auf einer Seite = Platzhalterblock divi/global-layout mit {"globalModule":"<ID>","blockName":"divi/<typ>","localAttrs":{…}} und den Kindern als innerBlocks (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, Filter divi.serializedPost.parseFlatModuleObjectIntoBlockArray.nested: alle Attribute außer globalModule, localAttrsMap, localChildren, globalParent, blockName, globalModuleTemplate wandern nach localAttrs). Kinder innerhalb einer globalen Vorlage tragen globalParent (Conversion.php:1491-1494). Modul-Metadaten: divi/global-layout hat keine Attribute (builder-5/server/_all_modules_metadata.php:18550-18557).
  • F7: Ausgabe per Verweis. Beim Rendern ersetzt BlockParser jeden divi/global-layout durch 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 Schnappschuss localAttrs werden nur die Attribute übernommen, die die Vorlage in localAttrsMap als „nicht synchronisiert“ führt (apply_local_attrs_filtering, BlockParserStore.php:348); die Kinder aus der Seite nur, wenn die Vorlage localChildren: true hat (:1307-1311). Die Seitenkopie ist also ein Schnappschuss, maßgeblich ist der Library-Post.
  • F8: Keine Expansion bei REST-POST. BlockParser überspringt die Expansion bei MigrationContext, 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_content im 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 vorher prepare_content_for_db). Recht: edit_posts + et_pb_is_allowed('edit_global_library') (:1494-1500) – ohne edit_post auf 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-3605 maybe_deglobalize_nested_global_modules: Platzhalter → blockName mit localAttrs als Attribute, globalParent entfernt). Divi selbst liest globalModule aus Markup per String-Scan, weil parse_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 braucht divi_library + save_library (builder/functions.php:340-346), globale Einträge zusätzlich edit_global_library (functions.php:366-372; im Builder core.php:4248-4262). theme_builder und read_dynamic_content_custom_fields sind „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_settings leer) → Standardwerte.
  • F13: Live-Bestand: 0 et_pb_layout, 0 et_template, 0 et_theme_builder, 0 TB-Layouts, kein Inhalt mit globalModule (Probe s1.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), alle capability_type post, show_ui false, show_in_rest false; Layouts unterstützen revisions (:184, 216, 248), Vorlagen nicht (:152).
  • F15: Live- und Entwurfsstand: et_theme_builder_get_theme_builder_post_id($live) sucht den TB-Post mit Status publish (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_template am TB-Post, mit Sicherung in der Option et_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() ohne edit_others_posts (:1464-1466); neue Vorlagen sofort publish (:1515-1521); Layout-IDs nur übernommen, wenn der passende Typ und publish (:1486-1496); Bedingungen sanitize_text_field, dedupliziert (:1565-1583). Die Funktion hängt die Vorlage nicht an den TB-Post – das macht nur et_theme_builder_api_save (api.php:223-243).
  • F18: et_theme_builder_insert_layout($options) (theme-builder.php:1643-1667): wp_die() ohne edit_others_posts, wp_insert_post mit post_status publish (kses!), Term layout_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). Danach et_theme_builder_clear_wp_cache('all') und ET_Core_PageResource::remove_static_resources('all','all') (api.php:249-254).
  • F20: api.php wird nur bei is_admin() || wp_doing_ajax() geladen (theme-builder.php:50-61); im REST-Kontext fehlen die et_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 (nur ThemeBuilder/Layout.php, ThemeBuilder.php für die Ausgabe).
  • F21: Bedingungs-IDs mit Trenner : (theme-builder.php:28): singular:post_type:<pt>:all (:703-710), archive:post_type:<pt> (nur post oder has_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 einen validate-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 mit appearance.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ätzlich edit_others_posts.

1.3 Dynamic Content, Pods, Loop

  • F24: DynamicContentOptions::get_options($post_id, $context) sammelt alles über den Filter divi_module_dynamic_content_options (builder-5/server/Packages/Module/Layout/Components/DynamicContent/DynamicContentOptions.php:85-133). Live für Seite 831: 57 Optionen, davon 34 loop_*, post_meta_key (Felder before|after|select_meta_key|meta_key|date_format|custom_date_format|enable_html) und je Post-Typ post_link_url_<pt> mit Feld post_id.
  • F25: Meta-Schlüssel-Liste: „meistgenutzte“ Meta-Schlüssel der ganzen Website plus ACF-Felder – nur mit read_dynamic_content_custom_fields oder im Kontext display (DynamicContentOptionPostMetaKey.php:80-140). Pods kennt Divi nicht.
  • F26: Ausgabe von custom_meta_<key>: Wert über get_post_meta/ACF, Filter divi_module_dynamic_content_resolved_custom_meta_value (DynamicContentOptionPostMetaKey.php:404), dann esc_html ohne enable_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> mit settings.post_id, Ausgabe esc_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 über loop_*-Optionen; die Expansion läuft nur beim Rendern (BlockParser.php:895-905).

1.4 Stand im Plugin

  • F29: ContentSchema::EXCLUDED schließt et_pb_layout, et_theme_builder, et_template und die drei TB-Layout-Typen aus (src/Integrations/WordPress/Schema/ContentSchema.php:19-24); PostGuard::editable liefert dafür not_found. Die Divi-Werkzeuge erreichen Library und TB heute nicht.
  • F30: Opak sind Blöcke mit globalModule, divi/global-layout oder nicht dekodierbaren Attributen (src/Integrations/Divi/BlockTree/Parser.php:56); Block::setAttrs wirft 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_init im 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 von et_pb_layout und et_header/body/footer_layout (Spec §5.1). Umsetzung: eine DiviTarget-Richtlinie neben PostGuard (Typ, Recht, Status-Regel je Typ), die DiviPageLoader verwendet; ContentSchema::EXCLUDED bleibt (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/-outline liefern für sie global_id, block_name und 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>" in post_content, wie Divi F10) und verlangt bei mehr als einer veröffentlichten Instanz confirm: 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_library und edit_post auf 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 mit read_dynamic_content_custom_fields (F25). Weil et_theme_builder_store_template/insert_layout bei fehlendem Recht wp_die() aufrufen (F17, F18), prüft das Plugin vorher selbst. et_pb_is_allowed steckt in einem Adapter (E15). – Kosten: ein Redakteur mit WP-Rechten, aber ohne Divi-Rolle, bekommt forbidden (gewollt, wie im Builder).
  • E4 – Library-Einträge legt das Plugin selbst an (kein et_pb_submit_layout, keine Builder-Route): wp_insert_post mit leerem Inhalt und Status publish (Divi kennt keine Library-Entwürfe, F2), Terme/Meta wie F2, danach Inhalt über DiviSaver::saveNew im kses-Fenster (D7, D11-Nachtrag), eingewickelt in divi/placeholder (F4), Flags wie DiviFlags. Ist ein Schritt fehlerhaft, wird der Entwurf endgültig gelöscht (wie lit/content-create). – Grund: et_pb_submit_layout ist 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-insert als Kopie oder globale Instanz. Kopie: Inhalt ohne divi/placeholder, verschachtelte globale Platzhalter entglobalisiert wie Divi (F10), eingefügt wie lit/divi-insert (StructureRules, AdminLabel). Globale Instanz: das Plugin erzeugt <!-- wp:divi/global-layout {"globalModule":"<id>","blockName":"<Wurzeltyp>"} --><!-- /wp:divi/global-layout --> ohne localAttrs (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 leere localAttrs/fehlende innerBlocks anders 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 ohne unfiltered_html werden 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 Divis before/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_layout mit leerem Inhalt, Inhalt danach über DiviSaver::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, nie et_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 aus et_theme_builder_get_flat_template_settings_options() plus deren validate-Callback, Post-IDs mit read_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 in lit/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 (mit id → Detail; ersetzt lit/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-insert und lit/divi-node-copy folgen zusätzlich dem Modus von lit/divi-insert). Destruktiv-Hinweis: lit/library-make-global (ersetzt Knoten), lit/tb-assign (öffentliche Wirkung). – Kosten: lit/library-get aus 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) und confirm: true je Seite mit tree_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 mit cursor, 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 nach tree_rev.
  • E12 – Dynamic Content. lit/divi-dynamic-sources(post_type) liefert DynamicContentOptions::get_options für einen Beispiel-Post des Typs (sonst 0), ohne loop_* (S36), dazu Pods-Felder des Typs aus PodsFieldSource mit 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> mit settings.post_id (F27), Prüfung read_post, kein Papierkorb; nur in URL-Feldern; (b) lit/guide mit topic: "all" (alle Themen in einem Aufruf, Größenlimit); (c) S19: lit/divi-design-system mit Filter (section: colors/variables/presets/fonts, module für Presets) und global_id in node-get; (d) lit/page-render-summary meldet 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/Prompt globale-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) → Guide theme-builder, Prompt custom-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 (DiviModules und DesignSystemReader gibt es schon; neu DiviLibraryStore, DiviThemeBuilder, DiviRoles), die Funktions-/Klassen-Existenz und Signaturen prüft und bei Abweichung unsupported statt Fatal liefert; lit/site-status zeigt 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-Skript tests/Integration/divi-export-library.php exportiert post_content, Terme, Meta und TB-Meta als builder-library-*.html / builder-tb-*.json (wie D12). Roundtrip-Test läuft automatisch mit. (3) DDEV-Smoke divi-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_content von 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_terms mit bestehenden Term-IDs; neue Terme nur mit manage_categories); keine Builder-Route und kein et_pb_create_layout mit 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-Änderungen remove_static_resources('all','all',true) und et_theme_builder_clear_wp_cache('all') (Spec §5.6 Schritt 5). – Kosten: Review-Pflicht wie D7.

3. Fragen an den Benutzer (nach Wichtigkeit)

  1. Sollen neue Theme-Builder-Vorlagen sofort wirken? Divi kennt für Vorlagen keinen Entwurf.
    • (a) Deaktiviert anlegen, Aktivieren nur ausdrücklich mit lit/tb-assign und 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.
  2. 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: true und Liste der betroffenen Seiten. Empfehlung.
    • (b) Nur Administratoren (unfiltered_html/manage_options).
    • (c) Globale Einträge nur lesen, Änderungen nur im Builder.
  3. 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).
  4. 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.
  5. 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 mit globalParent, ohne Kinder selbstschließend – statt der minimalen Form ohne localAttrs. Byte-Test gegen page--globale-instanzen.html.
  • Neuer Befund 9: Bibliothekseinträge aus Divis Dialog haben \r\n zwischen 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-save mit scope: "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: StoredNodeGuard prü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, wenn canonical() 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, #anker bleiben 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) und lottie.innerContent (P19 – src lä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 immer publish); scope: "global" braucht zusätzlich edit_global_library (P7). Ohne das Divi-Recht „Divi-Bibliothek“ (oder mit deaktivierter Gruppe, P9) ist jede Bibliotheks-ID not_found, byte-gleich mit einer fehlenden ID (P12); ohne edit_post auf dem Eintrag forbidden ohne Titel. lit/library-list listet nur Einträge mit edit_post und liest höchstens 500 Zeilen je Aufruf.
  • E9 umgesetzt mit: lit/divi-node-copy und lit/divi-dynamic-sources in 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-insert und lit/divi-node-copy folgen zusätzlich dem Zustand von lit/divi-insert (M2). P13 in 3a nur dokumentiert (Guide „Rechte“, Grenze): bei deaktivierter Gruppe oder ohne divi_library nennen Outline/node-get/Render-Auszug einer Seite noch die ID globaler Module; der Eintrag selbst bleibt not_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-delete nutzt dasselbe confirm, sein confirm_required nennt dann ebenfalls die betroffenen Seiten. P8a: die Bestätigung wird abgelehnt, wenn der Benutzer einen Eintrag mit Status publish, private oder future, der den Eintrag zeigt, nicht bearbeiten darf (auch TB-Layouts und andere Bibliothekseinträge); Entwürfe blockieren nicht. Der Probelauf nennt solche IDs vorab in blocked_ids (P14). Revisionen aus: abgelehnt ohne unfiltered_html (die Sicherung liefe durch kses) oder bei deaktiviertem Papierkorb (P9); scheitert das Speichern nach einer Sicherung, nennt der Fehler backup_id (P14). Cache-Leerung für alle Seiten und den Theme Builder.
  • P1: lit/divi-replace-text speichert normale Bibliothekseinträge über DiviWriter::commit(); globale nie (die Ziele tragen kein confirm) – das Ergebnis nennt die betroffenen Seiten und verweist auf lit-divi-update mit confirm.
  • Bibliothekseinträge bekommen keine Divi-Flags (Befund 4); _et_pb_row_layout wird nicht geschrieben (Befund 5).
  • E13a: {{link:<ID>}} nur in URL-Feldern; Ziel muss existieren, read_post bestehen, nicht Papierkorb, auto-draft oder inherit sein – 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-sources listet nur textartige Felder; Beziehungs-/Dateifelder („nur IDs“), Tabellen-Speicher und unbekannte Feldtypen (P9) stehen unter omitted; Auswahlfelder zeigen den gespeicherten Wert, nicht die Beschriftung. Der Beispiel-Post ist nur einer, den der Benutzer bearbeiten darf.
  • E15: Adapter DiviRoles, DiviLibraryStore, Prüfung DiviCompatibility in lit-site-status (problems je Komponente).
  • E13d umgesetzt als Hinweis in notes; eine eigene Expansion globaler Module im Auszug unterbleibt.
  • Tests: die Unit-Suite läuft mit memory_limit 512M (phpunit.xml.dist und composer 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).

7. Umsetzung Etappe 3b (Plan 2026-09-27-etappe-3b-theme-builder.md)

Rulings Q1–Q25: .superpowers/sdd/2026-09-27-etappe-3b-theme-builder/progress.md.

  • E7 präzisiert: Layouts und neue Vorlagen über et_theme_builder_insert_layout/et_theme_builder_store_template mit Rechteprüfung davor und wp_die-Sperre währenddessen; Zuordnung zur Live-Liste, Bedingungen und _et_enabled als Nachbildung von Divis Meta-Schreibweise (store_template würde bei bestehenden Vorlagen auch Standard-Kennzeichen, Titel und Onboarding-Meta neu schreiben). Nach dem Anlegen Rücklesen; Abweichung = alles zurücknehmen, auch Posts, die Divi vor einem Fehler schon eingefügt hatte (Q19).
  • E8/Antwort F1 umgesetzt als eigenes Tool lit/tb-activate (statt enabled in lit/tb-assign); neue Vorlagen sind immer deaktiviert. Jede andere Änderung, die Besucher sofort sähen (Bedingungen aktiver Vorlagen, Layouts aktiver Vorlagen), ist zuerst ein Probelauf und braucht confirm; Layouts mit der Sicherung aus VisibleEdits (Q2, Q9). Aktiv = zugeordnet und _et_enabled, unabhängig vom Post-Status (Q8).
  • Der Ausschalter (lit/tb-activate mit enabled: false) geht immer: auch bei TB-Entwurf, dann mit Warnung (Q20), und bei einer aktiven Vorlage im Papierkorb (Q16).
  • TB-Editor: Ablehnung bei TB-Entwurf; neue Vorlagen hängen sofort an der Live-Liste; lit/tb-list zeigt vom Theme Builder entfernte Vorlagen (detached), lit/tb-assign mit reattach ordnet sie deaktiviert wieder zu (nur mit aktiven Layouts, Q8/B10). Befunde 10–12: tests/Fixtures/divi/stage3b/README.md.
  • E3 für den Theme Builder: edit_others_posts, edit_theme_options (Q15) und Divis Rollen-Recht „Theme Builder“, je Vorlage/Layout edit_post, zum Anlegen die Veröffentlichen-Rechte. Nicht bearbeitbare Vorlagen antworten wie fehlende (Q18); aktive davon nur als Anzahl in Liste und Probeläufen von lit/tb-assign/lit/tb-activate (Q21) und der Layout-Änderungen (hidden_templates; die Rückfrage gilt trotzdem für alle aktiven Vorlagen, Q22).
  • Bedingungen nur aus Divis Katalog; Objekte lesbar (Begriffe: assign_term); strenger als Divi: Autoren-Bedingungen (archive:user:id:) nur mit list_users (Q10).
  • E9: eigene Gruppe „Divi Theme Builder“ (divi-theme-builder); alle neuen Tools indirekt, 22 direkte Tools.
  • E10/E11 umgesetzt mit Fingerprint (Struktur/Inhalt). „Inhaltsgleich“ heißt gleiche Bytes einschließlich Textteilen zwischen Blöcken und Inhalt von Core-Blöcken, nur Admin-Labels ausgenommen (Q25); ersetzt wird nur auf Seiten und Beiträgen (page, post), die das Konto bearbeiten darf – Theme-Builder-Layouts auch nicht als Quelle (Q24). Globale Einträge enthalten keinen Verweis auf einen Eintrag in irgendeiner Schreibweise (Q7). D10-Semantik beim Speichern mehrerer Seiten: Abbruch bei der ersten gescheiterten Seite, Fehler nennt geänderte, gescheiterte und unveränderte Seiten.
  • E12: Feldprüfung im Inhalt-Layout als Warnung gegen die Inhaltstypen der Vorlagen-Bedingungen, beide Feldformen (Q11).
  • P13 (vollständiges Ausblenden der Bibliotheks-IDs, auch im Suchen-und-Ersetzen) und P10 (Zielregeln der Vollform post_link_url_*, Bibliothekseinträge und Typen ohne Divi-Linkoption wie fehlende IDs, Q14) umgesetzt.
  • Restrisiken: P25 (ungewöhnliche Schreibweisen globaler Verweise), dazu Divis erneutes Auswerten von Blöcken in Shortcode-Modulen und WooCommerce-Textmodulen (dokumentiert im Guide divi-library); das Präfilter-Orakel von lit/divi-replace-text (Q13) und die Race-Bedingungen zwischen Prüfen und Schreiben bleiben für Etappe U.
  • Server-Instructions: Zeile „Divi Theme Builder: …“ nur bei aktiver, beschreibbarer Gruppe; der Ablauf „custom-post-type-vorlage“ steht im Guide theme-builder.