Files
WP-LIT-MCP/docs/superpowers/plans/2026-10-19-etappe-4d-theme-optionen-schriften.md
T

23 KiB
Raw Blame History

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-MCP anlegen oder ändern. Integrationsskripte stellen im EXIT-Trap alles wieder her, was sie ändern (et_divi byte-genau über serialize/base64, hochgeladene Schriften inkl. Dateien über FontsUtility::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 mit defined('ABSPATH') || exit;, declare(strict_types=1);, höchstens 120 Zeichen je Zeile. Nach jedem Task composer test und composer lint sauber (composer test = php -d memory_limit=512M vendor/bin/phpunit).
  • Divi-Grenze (Divi-Absicherung §3): Divi-Aufrufe nur in Klassen aus DiviAdapters::CLASSES mit Manifest; jedes Divi-Symbol steht mit Fähigkeiten im Manifest; DiviBoundaryTest und DiviFeatureAssignmentTest bleiben grün (die angepasste Tabelle gehört in denselben Task wie die Manifest-Änderung); neue Signaturen: fingerprints.json über wp lit-mcp divi-check --update-reference in 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 als validation_failed mit Feldpfaden → Probelauf mit diff, design_rev, warnings → mit confirm: true Sperre, Snapshot theme_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); false oder ein vom Eingabewert abweichendes Ergebnis ist ein Validierungsfehler (Divi würde false stillschweigend 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_options und et_pb_is_allowed('theme_customizer') (Divis Customizer-Regel); Lesen (theme-options-get): wie lit/divi-design-system (edit_posts). Font-Upload: upload_files und edit_theme_options und et_pb_is_allowed('custom_fonts_management') (Divis eigene Regel CustomFontController::store_permission() plus die Plugin-Regel; Spec §10 nannte irrtümlich use_visual_builder).
  • Exposition: Neue Tools sind indirekt (über mcp-adapter-execute-ability), Gruppe divi, Annotations wie die Preset-Tools (write/destructive); Texte nennen indirekte Tools lit/<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 mit Functions\expect() prüfen. Reine Klassen erben von PHPUnit\Framework\TestCase. TDD: Test zuerst, RED-Lauf, Code, GREEN. Adapter-Tests ersetzen Divi-Klassen per Mockery::mock('alias:…') mit @runInSeparateProcess (Vorbild GlobalColorsAdapterTest). 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 Plugins postlos und asynclistry; vorher Zustand mit ddev exec wp plugin list notieren 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 Mirror customizer-typography (Standards/Bereiche der 20 Settings) trägt theme-option-read und -write; die Schriftlisten-Aufrufe tragen theme-option-write, font-upload und variable-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 in ThemeOptionSpec als Literale nachgebaut; der Mirror auf et_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 Eingabewert null setzt zurück (Divi: et_delete_option); 'none' und false werden abgelehnt (Divi speichert die Standardschrift als false, 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); get nennt den effektiven Wert und default.
  • W4 Bereiche prüft das Plugin: Divis Sanitizer (absint, intval, floatval, Auswahl-Sanitizer → false) klemmen nicht; ThemeOptionSpec prüft min/max/step/choices der Customizer-Controls. body_header_style nimmt genau einen Wert (italic, uppercase, underline) oder null (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_failed mit 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ür heading_font, body_font, primary_nav_font, secondary_nav_font und Variablen vom Typ fonts. 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 aus get_option('et_divi') mit Rohwert und Typ (array<string, int|float|string|false>); ein fehlender Schlüssel fehlt im Array. ThemeOptionBook normalisiert (nur Whitelist, Schlüsselreihenfolge fest) und liefert rev(). 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') und et_pb_force_regenerate_templates()). Zurücklesen über get_option('et_divi') (nicht über GlobalData::get_customizer_fonts(), das static cacht). Restore ist ein vollständiges Ersetzen der Whitelist (mayRemove = true). Lost-Update-Risiko von et_update_option (schreibt das ganze Array aus dem Request-Global) ist dokumentiert; design_rev und Sperre mindern es.
  • W7 Keine Fundstellen: Theme-Optionen haben keinen Seitenbezug; der Probelauf liefert kein affected und die Warnung „wirkt auf die gesamte Website“ (bei Schriften zusätzlich „wirkt auch auf den Builder“). DesignPlan::usages bleibt null.
  • W8 Font-Upload-Weg: FontInstaller::install() ruft FontsUtility::font_add($files, $name, $settings, ['action' => 'wp_handle_upload_rest']) mit Temp-Dateien (wp_tempnam, wie AiAgentImageUtility::install_to_custom_fonts()); jede Datei vorab durch HooksRegistration::check_filetype_and_ext_font(); nach font_add werden die gelieferten font_file-Schlüssel gegen die Eingabe verglichen (Divi meldet Teilerfolg als Erfolg) – Abweichung → FontsUtility::font_remove($name) und Fehler. Statt eines Nachbaus des et_uploaded_fonts-Eintrags (Spec §8.2) ein Mirror font-install auf AiAgentImageUtility::install_to_custom_fonts (Aufrufkonvention). Erlaubte Formate: woff2, woff, ttf, otf (kein eot); Gewichte all oder Liste aus 100…900 (Plugin prüft, Divi nicht); generic_family aus serif|sans-serif|monospace|cursive|fantasy (Standard sans-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öchstens min(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) wie lit/media-upload-from-url über den geteilten RemoteFileFetcher.
  • W10 Probelauf des Uploads: ohne confirm lädt das Tool die Dateien wirklich herunter (nur Temp-Dateien, danach gelöscht), prüft alles und antwortet mit Errors::confirmRequired (Name, Dateien mit Format/Größe/SHA-256, Gewichte, Familie, „wirkt auf …“-Hinweis). Mit confirm: true lädt es erneut, prüft erneut und installiert; das Protokoll nennt die SHA-256-Werte. Kein Snapshot; Rollback bei Fehler über font_remove.
  • W11 Restore: DiviDesignRestoreAbility bekommt ThemeOptionsRestorePlanner (area() theme_options); die Meldung „Theme-Optionen folgen mit Etappe 4d“ entfällt (ein unbekannter Bereich bleibt unsupported); Rechte und Fähigkeiten wie beim Schreiben.
  • W12 Schrift-Variablen: DiviVariablesSetAbility prüft Variablen vom Typ fonts zusätzlich gegen FontCatalog (W5); VariableValue bleibt 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_resources wirkungslos ohne angemeldeten Benutzer (der Prozess hat einen, Smokes laufen mit --user).
  • W14 Rechte-Texte: DesignRights::themeOptions(DesignSystemWriter, ThemeOptionsAdapter) und DesignRights::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