Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
23 KiB
Etappe 4d – Designsystem: Theme-Optionen und Schriften – Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Der KI-Assistent liest und ändert die Design-Theme-Optionen von Divi (Schriften, Größen, Layout – lit/divi-theme-options-get, lit/divi-theme-options-update), lädt eigene Schriftdateien von einer URL hoch (lit/divi-fonts-upload), bekommt bei unbekannten Schriftnamen Vorschläge (auch bei Schrift-Variablen), und kann Snapshots des Bereichs theme_options wiederherstellen (lit/divi-design-restore) – mit Probelauf, confirm, Snapshot (Theme-Optionen) und Zurücklesen.
Architecture: Die 4a-Pipeline DesignChange bleibt unverändert; neu sind die DesignArea ThemeOptionsArea mit reinen Klassen (ThemeOptionSpec, ThemeOptionBook, ThemeOptionDiff, FontSuggest) und drei kleinen Divi-Adaptern (ThemeOptionsAdapter, FontCatalog, FontInstaller) mit eigenen Fähigkeiten (theme-option-read, theme-option-write, font-upload). Divis Customizer-Standards und -Bereiche stehen nur als Literale in et_divi_customizer_theme_settings(); sie werden als Tabelle (ThemeOptionSpec) nachgebaut und über einen Mirror mit Fingerabdruck abgesichert. Der Font-Upload ist KEIN Pipeline-Bereich (keine Snapshots, Spec A2): eigener Probelauf/confirm-Ablauf, Download über einen aus MediaImporter herausgelösten, geteilten RemoteFileFetcher, Installation über Divis FontsUtility::font_add() im Prozess (action: wp_handle_upload_rest, wie Divis eigener KI-Pfad).
Tech Stack: PHP ≥ 8.1, WordPress 7.x, Divi 5.15.1 (et_update_option/et_delete_option, Customizer-Sanitizer, et_builder_get_fonts/_google_fonts/_websafe_fonts/_custom_fonts, FontsUtility::font_add/font_remove, HooksRegistration::check_filetype_and_ext_font, et_pb_is_allowed – nur über die drei neuen Adapter), PHPUnit 9.6 + Brain Monkey + Mockery, phpcs (WPCS, PHPCompatibilityWP), DDEV + bash/jq-Smokes.
Spec: docs/superpowers/specs/2026-10-16-etappe-4-designsystem-design.md (§3, §4, §5, §8, §10, §11, §13, §14 Schritt 7), Entscheidungen docs/superpowers/notes/2026-09-28-etappe-4-entscheidungen-entwurf.md (G3, G6, G10, A1, A2, A8, A9 – verbindlich, soweit unten nicht durch Rulings W1–W14 geändert), Datenformate docs/superpowers/notes/2026-09-28-etappe-4-divi-formate.md §4 und der Nachtrag 4d in Task 11, Recherche 5.15.1: docs/superpowers/notes/2026-10-19-etappe-4d-divi-recherche.md (Task 11 legt sie ab; bis dahin die Kopie …/scratchpad/research-4d-divi.md des Planers – die Task-Autoren haben sie gelesen), Plan 4c (2026-10-19-etappe-4c-farben-variablen.md) als Vorbild; der Code ist maßgeblich, wo er von den Plänen abweicht.
Voraussetzung: Branch etappe-4 (= main), Stand 2307027 (4a, 4b, 4c fertig), 3121 Unit-Tests grün (composer test), composer lint sauber.
Teil von Etappe 4: 4a, 4b, 4c (fertig) → 4d (dieser Plan) → 4e Schleifen-Inhalte, Guides, Audit, Version.
Global Constraints
- Dateien nur im Plugin-Verzeichnis
/home/janniclas/Projekte/WordPress/wp-content/plugins/WP-LIT-MCPanlegen oder ändern. Integrationsskripte stellen im EXIT-Trap alles wieder her, was sie ändern (et_divibyte-genau über serialize/base64, hochgeladene Schriften inkl. Dateien überFontsUtility::font_remove, Seiten, Variablen). - PHP ≥ 8.1 ohne 8.2+-Features; WordPress ≥ 6.9; Divi 5.15.1. Namespace
LIT\MCP\→src/, PSR-4, eine Klasse pro Datei, jede Datei mitdefined('ABSPATH') || exit;,declare(strict_types=1);, höchstens 120 Zeichen je Zeile. Nach jedem Taskcomposer testundcomposer lintsauber (composer test=php -d memory_limit=512M vendor/bin/phpunit). - Divi-Grenze (Divi-Absicherung §3): Divi-Aufrufe nur in Klassen aus
DiviAdapters::CLASSESmit Manifest; jedes Divi-Symbol steht mit Fähigkeiten im Manifest;DiviBoundaryTestundDiviFeatureAssignmentTestbleiben grün (die angepasste Tabelle gehört in denselben Task wie die Manifest-Änderung); neue Signaturen:fingerprints.jsonüberwp lit-mcp divi-check --update-referencein DDEV neu erzeugen (Befehl und Prüfung wie in Task 2 des Plans 4c). Alle übrigen neuen Klassen sind reines PHP ohne WordPress- und Divi-Aufrufe; Ausnahmen nennt der Task ausdrücklich. - Pipeline (Spec §4): Theme-Optionen laufen durch
DesignChange::run()(Rechte → Eingabe prüfen, alle Fehler gesammelt alsvalidation_failedmit Feldpfaden → Probelauf mitdiff,design_rev,warnings→ mitconfirm: trueSperre, Snapshottheme_options, Schreiben, Zurücklesen +verify, Protokoll). Der Font-Upload nutzt die Pipeline nicht (kein Snapshot, A2), hat aber Probelauf +confirm, Rechte vorab, Rollback und Protokoll. - Werte: Jeder Wert einer Theme-Option wird vom Plugin geprüft (
ThemeOptionSpec::check: Typ, Bereich, Auswahl) UND durch Divis eigenen Customizer-Sanitizer des Schlüssels geschickt (ThemeOptionsAdapter::sanitize);falseoder ein vom Eingabewert abweichendes Ergebnis ist ein Validierungsfehler (Divi würdefalsestillschweigend speichern bzw. runden). Die fünf Hauptfarben, Button-Standards (all_buttons_*), Logo und SEO bleiben außen (G3, A8). - Rechte: Theme-Optionen schreiben und Restore:
edit_theme_optionsundet_pb_is_allowed('theme_customizer')(Divis Customizer-Regel); Lesen (theme-options-get): wielit/divi-design-system(edit_posts). Font-Upload:upload_filesundedit_theme_optionsundet_pb_is_allowed('custom_fonts_management')(Divis eigene RegelCustomFontController::store_permission()plus die Plugin-Regel; Spec §10 nannte irrtümlichuse_visual_builder). - Exposition: Neue Tools sind indirekt (über
mcp-adapter-execute-ability), Gruppedivi, Annotations wie die Preset-Tools (write/destructive); Texte nennen indirekte Toolslit/<name>(ToolNamingTest);docs/guides/overview.md„Direkt sichtbar:“ bleibt unverändert; Guides folgen gesammelt mit 4e. - Sprache: Meldungen, Hinweise, Beschreibungen auf Deutsch mit echten Umlauten; neutral „KI-Assistent“, „MCP-Client“.
- Tests: Abilities über
LIT\MCP\Tests\Unit\TestCase(Brain Monkey + Mockery,assertToolError); vorbelegte Stubs (wp_json_encode,is_wp_error,absint,wp_slash,wp_unslash,sanitize_text_field) nie mitFunctions\expect()prüfen. Reine Klassen erben vonPHPUnit\Framework\TestCase. TDD: Test zuerst, RED-Lauf, Code, GREEN. Adapter-Tests ersetzen Divi-Klassen perMockery::mock('alias:…')mit@runInSeparateProcess(VorbildGlobalColorsAdapterTest). Integration:cd /home/janniclas/Projekte/WordPress && timeout 900 ddev exec bash wp-content/plugins/WP-LIT-MCP/tests/Integration/<skript>.sh(läuft nur mit deaktivierten Pluginspostlosundasynclistry; vorher Zustand mitddev exec wp plugin listnotieren und danach wiederherstellen). - Kein clean-code-review-Skill je Task (die globale CLAUDE.md-Regel zieht sonst die Antwort des Implementierers an sich); der Gesamtreview folgt am Ende (Task 11).
- Commits:
git commit -m "<Nachricht>" -m "Co-Authored-By: Claude <Modellname> <noreply@anthropic.com>"mit dem Namen des ausführenden Modells; nur die Dateien des Tasks stagen.
Entscheidungen für 4d (Rulings, verbindlich)
- W1 Drei Fähigkeiten:
DiviFeature::ThemeOptionRead(theme-option-read, „Theme-Optionen lesen“),ThemeOptionWrite(theme-option-write, „Theme-Optionen schreiben“, schreibend),FontUpload(font-upload, „Schriften hochladen“, schreibend).ThemeOptionsArea::feature()=ThemeOptionWrite. Der Mirrorcustomizer-typography(Standards/Bereiche der 20 Settings) trägttheme-option-readund-write; die Schriftlisten-Aufrufe tragentheme-option-write,font-uploadundvariable-write(die Schrift-Variablen werden gegen dieselbe Liste geprüft; ein Bruch sperrt bewusst alle drei). - W2 Whitelist (Spec §8.1, G3):
heading_font,body_font,primary_nav_font,secondary_nav_font,heading_font_weight,body_font_weight,body_font_size,tablet_body_font_size,phone_body_font_size,body_header_size,tablet_header_font_size,phone_header_font_size,body_font_height,body_header_height,body_header_spacing,body_header_style,content_width,gutter_width,section_padding,row_padding. Standards, Bereiche und Sanitizer-Namen je Schlüssel stehen in der Recherche (Tabelle A) und werden inThemeOptionSpecals Literale nachgebaut; der Mirror aufet_divi_customizer_theme_settings()(functions.php) sichert sie.shortcut:der Mirror hasht die ganze Funktion und schlägt bei jeder Customizer-Änderung an; bei zu häufigem Anschlagen auf einen engeren Ausschnitt umstellen (im Code kommentieren). - W3 Unset statt
'none': Ein Schlüssel ist „nicht gesetzt“ = Divi-Standard. Der Eingabewertnullsetzt zurück (Divi:et_delete_option);'none'undfalsewerden abgelehnt (Divi speichert die Standardschrift alsfalse, ein gespeichertes'none'wäre in Divi 5 ein echter Schriftname). Tablet-/Phone-Größen erben, solange sie nicht gesetzt sind (effektiver Standard = der größere Wert);getnennt den effektiven Wert unddefault. - W4 Bereiche prüft das Plugin: Divis Sanitizer (
absint,intval,floatval, Auswahl-Sanitizer →false) klemmen nicht;ThemeOptionSpecprüft min/max/step/choices der Customizer-Controls.body_header_stylenimmt genau einen Wert (italic,uppercase,underline) odernull(Divis Sanitizer lehnt Kombinationen ab). Zahlen dürfen als Zahl oder Ziffern-String kommen; gespeichert wird der Typ, den Divis Sanitizer liefert (int/float/String). - W5 Schriftnamen: gültig ist der exakte Familienname (Groß-/Kleinschreibung) aus
array_merge(et_builder_get_custom_fonts(), et_builder_get_fonts())(so prüft Divis Sanitizer). Unbekannt →validation_failedmit bis zu 5 ähnlichen Namen (FontSuggest, ohne Beachtung der Groß-/Kleinschreibung: Präfix, Teilstring,levenshtein). Die Liste wird je Request einmal geladen (et_builder_get_google_fonts()lädt 1,3 MB und kann einmal je Tag einen HTTP-Abruf auslösen). Gilt fürheading_font,body_font,primary_nav_font,secondary_nav_fontund Variablen vom Typfonts. Schriftnamen in Preset-/Modul-Attributen werden in 4d NICHT geprüft (Folgepunkt für 4e, in der Notiz festgehalten). - W6 Snapshot
theme_options:raw= genau die vorhandenen Whitelist-Schlüssel ausget_option('et_divi')mit Rohwert und Typ (array<string, int|float|string|false>); ein fehlender Schlüssel fehlt im Array.ThemeOptionBooknormalisiert (nur Whitelist, Schlüsselreihenfolge fest) und liefertrev(). Schreiben/Restore: Schlüssel im neuen Bestand →et_update_option, Whitelist-Schlüssel, die im neuen Bestand fehlen →et_delete_option; danach die Caches wie ein Customizer-Speichern (ET_Core_PageResource::remove_static_resources('all', 'all')undet_pb_force_regenerate_templates()). Zurücklesen überget_option('et_divi')(nicht überGlobalData::get_customizer_fonts(), dasstaticcacht). Restore ist ein vollständiges Ersetzen der Whitelist (mayRemove = true). Lost-Update-Risiko vonet_update_option(schreibt das ganze Array aus dem Request-Global) ist dokumentiert;design_revund Sperre mindern es. - W7 Keine Fundstellen: Theme-Optionen haben keinen Seitenbezug; der Probelauf liefert kein
affectedund die Warnung „wirkt auf die gesamte Website“ (bei Schriften zusätzlich „wirkt auch auf den Builder“).DesignPlan::usagesbleibtnull. - W8 Font-Upload-Weg:
FontInstaller::install()ruftFontsUtility::font_add($files, $name, $settings, ['action' => 'wp_handle_upload_rest'])mit Temp-Dateien (wp_tempnam, wieAiAgentImageUtility::install_to_custom_fonts()); jede Datei vorab durchHooksRegistration::check_filetype_and_ext_font(); nachfont_addwerden die geliefertenfont_file-Schlüssel gegen die Eingabe verglichen (Divi meldet Teilerfolg als Erfolg) – Abweichung →FontsUtility::font_remove($name)und Fehler. Statt eines Nachbaus deset_uploaded_fonts-Eintrags (Spec §8.2) ein Mirrorfont-installaufAiAgentImageUtility::install_to_custom_fonts(Aufrufkonvention). Erlaubte Formate:woff2,woff,ttf,otf(keineot); Gewichtealloder Liste aus100…900(Plugin prüft, Divi nicht);generic_familyausserif|sans-serif|monospace|cursive|fantasy(Standardsans-serif; Divi prüft nicht). - W9 Font-Namen und -Dateien: Name: 1–100 Zeichen, nur
A–Z a–z 0–9, Leerzeichen,_,-(Divi entfernt andere Zeichen stillschweigend – das Plugin lehnt ab und nennt den bereinigten Namen), nicht in Googles, Web-Safe- oder bereits hochgeladenen Schriften (ohne Beachtung der Groß-/Kleinschreibung; strenger als Divi). Dateien: höchstensmin(Limits::uploadBytes(), 5 MB)je Datei (A9), 1–4 Dateien (je Format höchstens eine), Magic Bytes (FontSignature:wOF2,wOFF,00 01 00 00/true= ttf,OTTO= otf) müssen zur Endung der Eingabe passen; URL-Regeln (nur öffentliche Hosts, Weiterleitungen geprüft, Zeitlimit) wielit/media-upload-from-urlüber den geteiltenRemoteFileFetcher. - W10 Probelauf des Uploads: ohne
confirmlädt das Tool die Dateien wirklich herunter (nur Temp-Dateien, danach gelöscht), prüft alles und antwortet mitErrors::confirmRequired(Name, Dateien mit Format/Größe/SHA-256, Gewichte, Familie, „wirkt auf …“-Hinweis). Mitconfirm: truelädt es erneut, prüft erneut und installiert; das Protokoll nennt die SHA-256-Werte. Kein Snapshot; Rollback bei Fehler überfont_remove. - W11 Restore:
DiviDesignRestoreAbilitybekommtThemeOptionsRestorePlanner(area()theme_options); die Meldung „Theme-Optionen folgen mit Etappe 4d“ entfällt (ein unbekannter Bereich bleibtunsupported); Rechte und Fähigkeiten wie beim Schreiben. - W12 Schrift-Variablen:
DiviVariablesSetAbilityprüft Variablen vom Typfontszusätzlich gegenFontCatalog(W5);VariableValuebleibt rein (die Listenprüfung liegt in der Ability,VariableValue.php:12„folgt mit 4d“ wird berichtigt). - W13 Divi-Beschränkungen als Grenzen dokumentieren:
et_get_option-/et_update_option-Lost-Update,body_header_style-Einzelwert, fehlende Bereichsprüfung in Divi,font_add-Teilerfolg,remove_static_resourceswirkungslos ohne angemeldeten Benutzer (der Prozess hat einen, Smokes laufen mit--user). - W14 Rechte-Texte:
DesignRights::themeOptions(DesignSystemWriter, ThemeOptionsAdapter)undDesignRights::fonts(FontCatalog)entsprechen den Rechten oben; Fehlertexte nennen das fehlende Recht und die Divi-Rolle („Theme-Anpassung“/„Eigene Schriften verwalten“).
Schnittstellenvertrag (Namen und Signaturen, die spätere Tasks voraussetzen)
Alle Klassen unter src/Integrations/Divi/Design/ (Namespace LIT\MCP\Integrations\Divi\Design), Tests unter tests/Unit/Integrations/Divi/Design/ (Namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design), sofern nicht anders genannt. Task-Autoren dürfen Details verfeinern, aber nur mit Eintrag unter ## ABWEICHUNGEN am Ende ihres Abschnitts.
// Release/DiviFeature.php (Task 1)
case ThemeOptionRead = 'theme-option-read'; // label 'Theme-Optionen lesen'
case ThemeOptionWrite = 'theme-option-write'; // label 'Theme-Optionen schreiben', isWrite() = true
case FontUpload = 'font-upload'; // label 'Schriften hochladen', isWrite() = true
// ThemeOptionsAdapter.php (Task 2) – class (nicht final) implements DiviAdapter, Manifest::DESIGN
public static function manifest(): Manifest;
/** @return array<string, int|float|string|false> vorhandene Whitelist-Schlüssel aus get_option('et_divi') */
public function read(): array;
/** Divis Customizer-Sanitizer des Schlüssels; false = Divi lehnt ab. @throws InvalidArgumentException unbekannter Schlüssel */
public function sanitize(string $key, mixed $value): mixed;
/** @param array<string, int|float|string|false> $set @param list<string> $unset @throws RuntimeException wenn das Zurücklesen nicht stimmt */
public function write(array $set, array $unset): array; // et_update_option / et_delete_option, dann Caches, liefert read()
public function canCustomize(): bool; // et_pb_is_allowed('theme_customizer'), fail closed ohne Divi
// FontCatalog.php (Task 2) – class (nicht final) implements DiviAdapter
/** @return list<string> exakte Familiennamen: hochgeladene + Google + Web-Safe, einmal je Request */
public function names(): array;
/** @return list<string> */ public function uploaded(): array;
/** @return list<string> Google + Web-Safe + hochgeladen (Kollisionsprüfung beim Upload) */ public function reserved(): array;
public function has(string $name): bool;
public function canManage(): bool; // et_pb_is_allowed('custom_fonts_management')
// FontInstaller.php (Task 8) – class (nicht final) implements DiviAdapter
/** @return list<string> Formate, die Plugin UND Divi (mime_types_font) erlauben: woff2, woff, ttf, otf */
public function formats(): array;
public function accepts(string $path, string $filename): bool; // HooksRegistration::check_filetype_and_ext_font
/** @param array<string, string> $files Endung => Temp-Dateipfad @return list<string> installierte Endungen @throws RuntimeException */
public function install(string $name, array $files, string $weights, string $family): array;
public function remove(string $name): void;
// DesignRights.php (Task 2) – zusätzlich
public static function themeOptions(DesignSystemWriter $writer, ThemeOptionsAdapter $options): ?WP_Error;
public static function fonts(FontCatalog $fonts): ?WP_Error; // upload_files + edit_theme_options + custom_fonts_management
// ThemeOptionSpec.php (Task 3) – reines PHP
public const KEYS = [ /* die 20 Schlüssel in der Reihenfolge von W2 */ ];
/** @return array{type: 'int'|'float'|'font'|'weight'|'style', label: string, default: int|float|string|null, min?: int|float, max?: int|float, step?: int|float, choices?: list<string>, inherits?: string} */
public static function definition(string $key): array;
public static function isKey(string $key): bool;
public static function check(string $key, mixed $value): ?string; // null = gültig (Typ/Bereich/Auswahl, ohne Schriftliste), sonst deutsche Meldung
public static function normalize(string $key, mixed $value): int|float|string; // "15" → 15, "1.7" → 1.7
public static function effective(string $key, array $stored): int|float|string|null; // gespeicherter Wert, sonst vererbter/Standardwert (W3)
// ThemeOptionBook.php (Task 3) – reines PHP, unveränderlich
public static function fromDivi(array $raw): self; // nur Whitelist, feste Reihenfolge
/** @return array<string, int|float|string|false> */ public function data(): array;
public function rev(): string; // Rev::of wie PresetBook/ColorBook
public function has(string $key): bool;
public function get(string $key): int|float|string|false|null;
public function with(string $key, int|float|string|false $value): self;
public function without(string $key): self;
// ThemeOptionDiff.php (Task 3) – reines PHP
/** @return list<array{key: string, label: string, action: string, before: mixed, after: mixed}> action: added|changed|reset */
public static function between(ThemeOptionBook $before, ThemeOptionBook $after): array;
public static function summary(array $diff): string; // 'Theme-Optionen: 1 gesetzt, 2 geändert, 1 zurückgesetzt.' / '… keine Änderung.'
// FontSuggest.php (Task 3) – reines PHP
/** @param list<string> $names @return list<string> höchstens $limit ähnliche Namen */
public static function similar(string $name, array $names, int $limit = 5): array;
// ThemeOptionsArea.php (Task 4) – implements DesignArea: name 'theme_options', label 'Theme-Optionen', feature ThemeOptionWrite
public function __construct(ThemeOptionsAdapter $options);
// DiviThemeOptionsGetAbility.php: __construct(ThemeOptionsAdapter, ?FontCatalog = null) – lit/divi-theme-options-get
// DiviThemeOptionsUpdateAbility.php: __construct(DesignSystemWriter, ThemeOptionsAdapter, FontCatalog, DesignChange) – lit/divi-theme-options-update
// RemoteFileFetcher.php (Task 7) – src/Integrations/Media/RemoteFileFetcher.php (Namespace LIT\MCP\Integrations\Media) – aus MediaImporter herausgelöst
// FontSignature.php (Task 8) – reines PHP: public static function detect(string $header): ?string; // 'woff2'|'woff'|'ttf'|'otf'
// FontNameRules.php (Task 8) – reines PHP: public static function check(string $name, array $reserved): ?string; // null = gültig
// DiviFontsUploadAbility.php (Task 8): __construct(FontCatalog, FontInstaller, RemoteFileFetcher, ChangeLog, …) – lit/divi-fonts-upload
// RestorePlanner (Task 6) – ThemeOptionsRestorePlanner implements RestorePlanner (area 'theme_options')
Dateistruktur
Neu (src/Integrations/Divi/Design/): ThemeOptionsAdapter, FontCatalog, FontInstaller, ThemeOptionSpec, ThemeOptionBook, ThemeOptionDiff, FontSuggest, ThemeOptionsArea, DiviThemeOptionsGetAbility, DiviThemeOptionsUpdateAbility, ThemeOptionsRestorePlanner, FontSignature, FontNameRules, DiviFontsUploadAbility; neu src/Integrations/Media/RemoteFileFetcher.php.
Geändert: Release/DiviFeature.php, Release/DiviAdapters.php, Release/fingerprints.json, Design/DesignRights.php, Design/DiviDesignRestoreAbility.php, Design/DiviVariablesSetAbility.php, Design/VariableValue.php (nur Kommentar), src/Integrations/Media/MediaImporter.php, DiviIntegration.php, Notizen/Spec (Task 11).
Neu (Tests): je Klasse eine Testdatei; tests/Integration/divi-theme-fonts-smoke.sh; ggf. eine kleine Schrift-Fixture unter tests/Fixtures/.
Geändert (Tests): DiviFeatureTest, DiviFeatureAssignmentTest, DiviToolFeaturesTest, DiviIntegrationTest, DiviDesignRestoreAbilityTest, DesignRightsTest, DiviVariablesSetAbilityTest, MediaImporterTest (und was grep -rn "PresetWrite\|preset-write\|VariableWrite\|variable-write" tests an Fähigkeitszählungen findet).
Task-Übersicht
| # | Task | Ergebnis |
|---|---|---|
| 1 | Fähigkeiten ThemeOptionRead/ThemeOptionWrite/FontUpload |
Enum, Label, Tests (Commit gemeinsam mit Task 2) |
| 2 | ThemeOptionsAdapter, FontCatalog, Manifest, Fingerabdrücke, DesignRights |
Divi-Grenze für Lesen/Schreiben/Schriftlisten |
| 3 | ThemeOptionSpec, ThemeOptionBook, ThemeOptionDiff, FontSuggest |
reiner Bestand der Theme-Optionen |
| 4 | ThemeOptionsArea, lit/divi-theme-options-get, lit/divi-theme-options-update |
Theme-Optionen lesen/schreiben |
| 5 | Schriftprüfung der Schrift-Variablen | lit/divi-variables-set prüft Typ fonts |
| 6 | ThemeOptionsRestorePlanner |
Restore für theme_options |
| 7 | RemoteFileFetcher aus MediaImporter herauslösen |
geteilter Download (Refactor, Verhalten gleich) |
| 8 | FontSignature, FontNameRules, FontInstaller, lit/divi-fonts-upload |
Schriften hochladen |
| 9 | Verdrahtung | DiviIntegration, Tabellen der Fähigkeiten |
| 10 | Smoke gegen echtes Divi | divi-theme-fonts-smoke.sh |
| 11 | Notizen, Recherche ablegen, Spec, Gesamtverifikation | Formate-Nachtrag 4d, Spec §8/§10, Review, Memory |