test: Divi 5 design system fixtures and format notes for Etappe 4

Seed script writes four global colors (one relative), one variable per
type, four module presets (one default) and two option group presets plus
the draft page "[Fixture] Designsystem" through Divi's own builder REST
routes; export script saves them to tests/Fixtures/divi/stage4/. Notes
document storage, write functions, side effects and permissions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-30 06:03:54 +02:00
co-authored by Claude Opus 5.5
parent 81da979a15
commit 2e4309cb42
12 changed files with 2396 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
# Divi-5-Fixtures für Etappe 4 (Designsystem: Farben, Variablen, Presets, Theme-Optionen)
Echte Daten aus Divi 5.2.1, erzeugt am 2026-09-28 auf der lokalen DDEV-Site (`https://wordpress.ddev.site:8443`). Vorher hatte die Site keine eigenen Designdaten: nur die fünf Customizer-Farben (alle auf Divi-Standard, in `et_divi` nicht gespeichert), keine Variablen, keine Presets.
Formate, Quellen mit Zeilenangaben und Stolpersteine: `docs/superpowers/notes/2026-09-28-etappe-4-divi-formate.md`.
## Wie die Daten entstanden sind
Skript `tests/Integration/divi-seed-stage4-design.php` (idempotent, findet Einträge über ihr „[Fixture] …“-Label wieder):
```
cd /home/janniclas/Projekte/WordPress
ddev exec wp eval-file wp-content/plugins/WP-LIT-MCP/tests/Integration/divi-seed-stage4-design.php
ddev exec wp eval-file wp-content/plugins/WP-LIT-MCP/tests/Integration/divi-export-stage4-fixtures.php
```
Das Seed-Skript schreibt **ausschließlich über die REST-Routen, die der Visual Builder selbst aufruft** – prozessintern per `rest_do_request()` als Administrator, mit Divis Routen-Nonce im Header `X-ET-Nonce`. Damit laufen Divis Argument-Schema, Sanitize-Callbacks, Berechtigungsprüfung und Speicherfunktionen genau wie beim Speichern im Builder:
| Bereich | Route | Divi-Funktion |
|---|---|---|
| Farben | `POST divi/v1/global-data/global-colors` | `GlobalDataController::update_global_colors` → `GlobalData::set_global_colors($data, true)` |
| Variablen | `POST divi/v1/global-data/global-variables` | `GlobalDataController::update_global_variables` → `GlobalData::set_global_variables()` |
| Presets | `POST divi/v1/global-data/global-preset/sync` | `GlobalPresetController::sync` → `GlobalPreset::prepare_data()` → `validate_preset_count()` → `save_data()` |
| Seite | `POST divi/v1/sync-to-server` | `SyncToServerController::update` (wie „Entwurf speichern“) |
Die Seite wurde vorher mit `wp_insert_post()` als leerer Entwurf angelegt und mit `et_builder_enable_for_post()` für den Builder freigeschaltet (wie Etappe 3). Die Aufteilung der Preset-Attribute in `styleAttrs`/`renderAttrs` stammt aus Divis eigener Attribut-Karte (`Conversion::get_preset_attrs_mapping()` / `Conversion::get_preset_attrs()`, derselbe Weg wie beim Import von Divi-4-Presets). IDs sind wie im Builder 10 Zeichen aus `[0-9a-z]` (`generateNanoUuid`, `global-data.js`).
Nicht angefasst: die fünf Customizer-Farben (nicht im Payload, `accent_color` & Co. bleiben ungesetzt), Theme-Optionen, Divi-4-Preset-Historie, alle übrigen Inhalte der Site.
## Angelegte Einträge
| Art | ID | Label/Name | Inhalt |
|---|---|---|---|
| Farbe | `gcid-q9swzy97df` | [Fixture] Holz dunkel | `#5b3a29` |
| Farbe | `gcid-989stx15zc` | [Fixture] Holz hell | relativ: Holz dunkel, `lightness +30` |
| Farbe | `gcid-pgtgy2j1i7` | [Fixture] Salbeigrün | `#7d9b76` |
| Farbe | `gcid-gg4lef6xns` | [Fixture] Sandbeige | `#efe6d8` |
| Variable `numbers` | `gvid-f6yq6mayfy` | [Fixture] Eckenradius | `8px` |
| Variable `numbers` | `gvid-5dec72fwsc` | [Fixture] Abstand Karte | `clamp(1.5rem, 4vw, 2.5rem)` |
| Variable `strings` | `gvid-7uckqqhmrh` | [Fixture] Slogan | `Handwerk aus Meisterhand – seit 1987` |
| Variable `images` | `gvid-qmc3cy1alq` | [Fixture] Werkstattbild | URL eines vorhandenen Bildes der Mediathek |
| Variable `links` | `gvid-nt8f6iz2qh` | [Fixture] Kontaktseite | `https://wordpress.ddev.site:8443/kontakt/` |
| Variable `fonts` | `gvid-d4a5bsz2gt` | [Fixture] Akzentschrift | `Merriweather` |
| Modul-Preset `divi/button` | `3gbmxlurey` | [Fixture] Button Primär | Hintergrund Holz dunkel, Schrift Sandbeige/600, Radius = Eckenradius |
| Modul-Preset `divi/text` | `hsiy1sjxt7` | [Fixture] Text Hinweis | Hintergrund Sandbeige, Radius, Innenabstand = Abstand Karte, **verschachteltes** Gruppen-Preset Fließtext |
| Modul-Preset `divi/blurb` | `vdcl6msnuo` | [Fixture] Blurb Leistung | Titel Akzentschrift/Holz dunkel/700, Rahmen Salbeigrün, Radius |
| Modul-Preset `divi/divider` | `g7kvfq5uh8` | [Fixture] Trenner Standard | **Standard-Preset** des Moduls; Linie Holz hell, 3px |
| Gruppen-Preset `divi/font-body` | `ja6o54jtlc` | [Fixture] Fließtext | aus `divi/text`, `content.decoration.bodyFont`; Akzentschrift, Holz dunkel, 17px/1.8em |
| Gruppen-Preset `divi/spacing` | `apzj7e17ok` | [Fixture] Abstand Karte | aus `divi/blurb`, `module.decoration.spacing`; Innenabstand = Abstand Karte, Außenabstand unten 24px |
| Seite | 3182 | [Fixture] Designsystem | Entwurf; nutzt alle Presets und die Variablen string/link/image |
`divi/divider` wird auf keiner anderen Seite der Site verwendet – das Standard-Preset ändert dort nichts.
## Dateien
| Datei | Inhalt |
|---|---|
| `global-colors.json` | `et_divi['et_global_data']` wie gespeichert und `GlobalData::get_global_colors()` (Customizer-Farben vorn; deren `lastUpdated` wird bei jedem Lesen neu erzeugt) |
| `global-variables.json` | Option `et_divi_global_variables` (dekodiert und als serialisierte Zeile), `GlobalData::get_global_variables()` und die PHP-Typen je Gruppe (`stdClass` – eine leere Gruppe erscheint im JSON als `{}`) |
| `presets.json` | Option `et_divi_builder_global_presets_d5`, `GlobalPreset::get_data()`, die Divi-4-Option `et_divi_builder_global_presets_ng`, Importkennzeichen |
| `presets-history.json` | Divi-4-Preset-Historie (`et_divi_builder_presets_history_meta`, keine Einträge) und die Migrationsflags aus `et_divi` |
| `et-divi-subset.json` | Theme-Optionen der Whitelist aus Spec §7: vorhandene Schlüssel mit Wert, fehlende Schlüssel, wirksame Akzentfarben und Customizer-Schriften |
| `page--designsystem.json` / `.html` | Post-Zeile, alle Meta-Einträge roh, `post_content` byte-genau |
| `manifest.json` | Divi-Version, Dateiliste, Post-ID |
## Prüfung im Frontend
Die Vorschau des Entwurfs (angemeldet, `?page_id=3182&preview=true`) enthielt am 2026-09-28:
- Klassen `preset--module--divi-button--3gbmxlurey`, `preset--module--divi-text--hsiy1sjxt7` mit `preset--group--divi-text--divi-font-body--nested--ja6o54jtlc`, `preset--group--divi-text--divi-font-body--ja6o54jtlc` (explizites Gruppen-Preset), `preset--module--divi-blurb--vdcl6msnuo` mit `preset--group--divi-blurb--divi-spacing--apzj7e17ok` und `preset--module--divi-divider--default` (Trenner ohne `modulePreset` → Standard-Preset);
- CSS-Regeln zu diesen Klassen mit `var(--gcid-…)`/`var(--gvid-…)`;
- `:root` mit `--gvid-f6yq6mayfy: 8px`, `--gvid-5dec72fwsc: clamp(…)`, `--gvid-d4a5bsz2gt: 'Merriweather'` und `--gcid-989stx15zc: hsl(from var(--gcid-q9swzy97df) calc(h + 0) calc(s + 0) calc(l + 30))`;
- aufgelöste Inhalte: Slogan-Text, `href="https://wordpress.ddev.site:8443/kontakt/"`, Bild-URL aus der Bild-Variable.
@@ -0,0 +1,58 @@
{
"option_name": "et_divi",
"present": {},
"absent": [
"heading_font",
"body_font",
"heading_font_weight",
"body_font_weight",
"primary_nav_font",
"secondary_nav_font",
"all_buttons_font",
"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",
"accent_color",
"secondary_accent_color",
"header_color",
"font_color",
"link_color",
"divi_logo"
],
"effective": {
"accent_colors": {
"primary": "#2ea3f2",
"secondary": "#2ea3f2",
"heading": "#666666",
"body": "#666666",
"link": "#2ea3f2"
},
"customizer_fonts": {
"--et_global_heading_font": {
"id": "--et_global_heading_font",
"label": "Überschrift",
"value": "Open Sans",
"status": "active",
"order": 1
},
"--et_global_body_font": {
"id": "--et_global_body_font",
"label": "Fließtext",
"value": "Open Sans",
"status": "active",
"order": 2
}
}
}
}
@@ -0,0 +1,116 @@
{
"stored": {
"option_name": "et_divi",
"key": "et_global_data",
"value": {
"global_colors": {
"gcid-q9swzy97df": {
"color": "#5b3a29",
"folder": "",
"label": "[Fixture] Holz dunkel",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-989stx15zc": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{\"lightness\":30}}})$",
"folder": "",
"label": "[Fixture] Holz hell",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-pgtgy2j1i7": {
"color": "#7d9b76",
"folder": "",
"label": "[Fixture] Salbeigrün",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-gg4lef6xns": {
"color": "#efe6d8",
"folder": "",
"label": "[Fixture] Sandbeige",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
}
}
}
},
"get_global_colors": {
"gcid-primary-color": {
"color": "#2ea3f2",
"folder": "customizer",
"label": "Primärfarbe",
"lastUpdated": "2026-09-28T00:22:52.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-secondary-color": {
"color": "#2ea3f2",
"folder": "customizer",
"label": "Sekundärfarbe",
"lastUpdated": "2026-09-28T00:22:52.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-heading-color": {
"color": "#666666",
"folder": "customizer",
"label": "Überschriftentextfarbe",
"lastUpdated": "2026-09-28T00:22:52.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-body-color": {
"color": "#666666",
"folder": "customizer",
"label": "Fließtextfarbe",
"lastUpdated": "2026-09-28T00:22:52.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-link-color": {
"color": "#2ea3f2",
"folder": "customizer",
"label": "Linkfarbe",
"lastUpdated": "2026-09-28T00:22:52.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-q9swzy97df": {
"color": "#5b3a29",
"folder": "",
"label": "[Fixture] Holz dunkel",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-989stx15zc": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{\"lightness\":30}}})$",
"folder": "",
"label": "[Fixture] Holz hell",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-pgtgy2j1i7": {
"color": "#7d9b76",
"folder": "",
"label": "[Fixture] Salbeigrün",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
},
"gcid-gg4lef6xns": {
"color": "#efe6d8",
"folder": "",
"label": "[Fixture] Sandbeige",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"status": "active",
"usedInPosts": []
}
}
}
@@ -0,0 +1,210 @@
{
"stored": {
"numbers": {
"gvid-f6yq6mayfy": {
"id": "gvid-f6yq6mayfy",
"label": "[Fixture] Eckenradius",
"value": "8px",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "numbers"
},
"gvid-5dec72fwsc": {
"id": "gvid-5dec72fwsc",
"label": "[Fixture] Abstand Karte",
"value": "clamp(1.5rem, 4vw, 2.5rem)",
"order": "2",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "numbers"
}
},
"strings": {
"gvid-7uckqqhmrh": {
"id": "gvid-7uckqqhmrh",
"label": "[Fixture] Slogan",
"value": "Handwerk aus Meisterhand – seit 1987",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "strings"
}
},
"images": {
"gvid-qmc3cy1alq": {
"id": "gvid-qmc3cy1alq",
"label": "[Fixture] Werkstattbild",
"value": "https://wordpress.ddev.site:8443/wp-content/uploads/2026/09/600.jpg",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "images"
}
},
"links": {
"gvid-nt8f6iz2qh": {
"id": "gvid-nt8f6iz2qh",
"label": "[Fixture] Kontaktseite",
"value": "https://wordpress.ddev.site:8443/kontakt/",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "links"
}
},
"fonts": {
"gvid-d4a5bsz2gt": {
"id": "gvid-d4a5bsz2gt",
"label": "[Fixture] Akzentschrift",
"value": "Merriweather",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "fonts"
}
}
},
"stored_raw": {
"option_name": "et_divi_global_variables",
"autoload": "off",
"option_value": "a:5:{s:7:\"numbers\";a:2:{s:15:\"gvid-f6yq6mayfy\";a:7:{s:2:\"id\";s:15:\"gvid-f6yq6mayfy\";s:5:\"label\";s:21:\"[Fixture] Eckenradius\";s:5:\"value\";s:3:\"8px\";s:5:\"order\";s:1:\"1\";s:6:\"status\";s:6:\"active\";s:11:\"lastUpdated\";s:24:\"2026-09-27T22:21:39.000Z\";s:12:\"variableType\";s:7:\"numbers\";}s:15:\"gvid-5dec72fwsc\";a:7:{s:2:\"id\";s:15:\"gvid-5dec72fwsc\";s:5:\"label\";s:23:\"[Fixture] Abstand Karte\";s:5:\"value\";s:26:\"clamp(1.5rem, 4vw, 2.5rem)\";s:5:\"order\";s:1:\"2\";s:6:\"status\";s:6:\"active\";s:11:\"lastUpdated\";s:24:\"2026-09-27T22:21:39.000Z\";s:12:\"variableType\";s:7:\"numbers\";}}s:7:\"strings\";a:1:{s:15:\"gvid-7uckqqhmrh\";a:7:{s:2:\"id\";s:15:\"gvid-7uckqqhmrh\";s:5:\"label\";s:16:\"[Fixture] Slogan\";s:5:\"value\";s:38:\"Handwerk aus Meisterhand – seit 1987\";s:5:\"order\";s:1:\"1\";s:6:\"status\";s:6:\"active\";s:11:\"lastUpdated\";s:24:\"2026-09-27T22:21:39.000Z\";s:12:\"variableType\";s:7:\"strings\";}}s:6:\"images\";a:1:{s:15:\"gvid-qmc3cy1alq\";a:7:{s:2:\"id\";s:15:\"gvid-qmc3cy1alq\";s:5:\"label\";s:23:\"[Fixture] Werkstattbild\";s:5:\"value\";s:67:\"https://wordpress.ddev.site:8443/wp-content/uploads/2026/09/600.jpg\";s:5:\"order\";s:1:\"1\";s:6:\"status\";s:6:\"active\";s:11:\"lastUpdated\";s:24:\"2026-09-27T22:21:39.000Z\";s:12:\"variableType\";s:6:\"images\";}}s:5:\"links\";a:1:{s:15:\"gvid-nt8f6iz2qh\";a:7:{s:2:\"id\";s:15:\"gvid-nt8f6iz2qh\";s:5:\"label\";s:22:\"[Fixture] Kontaktseite\";s:5:\"value\";s:41:\"https://wordpress.ddev.site:8443/kontakt/\";s:5:\"order\";s:1:\"1\";s:6:\"status\";s:6:\"active\";s:11:\"lastUpdated\";s:24:\"2026-09-27T22:21:39.000Z\";s:12:\"variableType\";s:5:\"links\";}}s:5:\"fonts\";a:1:{s:15:\"gvid-d4a5bsz2gt\";a:7:{s:2:\"id\";s:15:\"gvid-d4a5bsz2gt\";s:5:\"label\";s:23:\"[Fixture] Akzentschrift\";s:5:\"value\";s:12:\"Merriweather\";s:5:\"order\";s:1:\"1\";s:6:\"status\";s:6:\"active\";s:11:\"lastUpdated\";s:24:\"2026-09-27T22:21:39.000Z\";s:12:\"variableType\";s:5:\"fonts\";}}}"
},
"get_global_variables": {
"numbers": {
"gvid-f6yq6mayfy": {
"id": "gvid-f6yq6mayfy",
"label": "[Fixture] Eckenradius",
"value": "8px",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "numbers",
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
},
"gvid-5dec72fwsc": {
"id": "gvid-5dec72fwsc",
"label": "[Fixture] Abstand Karte",
"value": "clamp(1.5rem, 4vw, 2.5rem)",
"order": "2",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "numbers",
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
}
},
"strings": {
"gvid-7uckqqhmrh": {
"id": "gvid-7uckqqhmrh",
"label": "[Fixture] Slogan",
"value": "Handwerk aus Meisterhand – seit 1987",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "strings",
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
}
},
"images": {
"gvid-qmc3cy1alq": {
"id": "gvid-qmc3cy1alq",
"label": "[Fixture] Werkstattbild",
"value": "https://wordpress.ddev.site:8443/wp-content/uploads/2026/09/600.jpg",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "images",
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
}
},
"links": {
"gvid-nt8f6iz2qh": {
"id": "gvid-nt8f6iz2qh",
"label": "[Fixture] Kontaktseite",
"value": "https://wordpress.ddev.site:8443/kontakt/",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "links",
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
}
},
"colors": {},
"fonts": {
"--et_global_heading_font": {
"id": "--et_global_heading_font",
"label": "Überschrift",
"value": "Open Sans",
"status": "active",
"order": 1,
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
},
"--et_global_body_font": {
"id": "--et_global_body_font",
"label": "Fließtext",
"value": "Open Sans",
"status": "active",
"order": 2,
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
},
"gvid-d4a5bsz2gt": {
"id": "gvid-d4a5bsz2gt",
"label": "[Fixture] Akzentschrift",
"value": "Merriweather",
"order": "1",
"status": "active",
"lastUpdated": "2026-09-27T22:21:39.000Z",
"variableType": "fonts",
"allowedActions": {
"editLabel": true,
"editValue": true,
"reorder": true,
"remove": true
}
}
}
},
"get_global_variables_php_types": {
"numbers": "stdClass",
"strings": "stdClass",
"images": "stdClass",
"links": "stdClass",
"colors": "stdClass",
"fonts": "stdClass"
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"divi_version": "5.2.1",
"builder_version": "5.2.1",
"files": [
"global-colors.json",
"global-variables.json",
"presets.json",
"presets-history.json",
"et-divi-subset.json",
"page--designsystem.json",
"page--designsystem.html"
],
"posts": {
"page--designsystem": 3182
}
}
@@ -0,0 +1,14 @@
<!-- wp:divi/placeholder --><!-- wp:divi/section {"module":{"meta":{"adminLabel":{"desktop":{"value":"Designsystem Abschnitt"}}}},"builderVersion":"5.2.1"} -->
<!-- wp:divi/row {"module":{"meta":{"adminLabel":{"desktop":{"value":"Designsystem Zeile"}}}},"builderVersion":"5.2.1"} -->
<!-- wp:divi/column {"module":{"decoration":{"sizing":{"desktop":{"value":{"flexType":"24_24"}}}}},"builderVersion":"5.2.1"} -->
<!-- wp:divi/heading {"module":{"meta":{"adminLabel":{"desktop":{"value":"Überschrift"}}}},"title":{"innerContent":{"desktop":{"value":"Designsystem-Fixture"}}},"builderVersion":"5.2.1"} /-->
<!-- wp:divi/text {"module":{"meta":{"adminLabel":{"desktop":{"value":"Text mit Modul-Preset"}}}},"modulePreset":["hsiy1sjxt7"],"content":{"innerContent":{"desktop":{"value":"\u003cp\u003eHinweis-Text mit dem Modul-Preset „[Fixture] Text Hinweis“ (enthält das Gruppen-Preset „[Fixture] Fließtext“).\u003c/p\u003e"}}},"builderVersion":"5.2.1"} /-->
<!-- wp:divi/text {"module":{"meta":{"adminLabel":{"desktop":{"value":"Text mit Gruppen-Preset"}}}},"groupPreset":{"content.decoration.bodyFont":{"presetId":["ja6o54jtlc"],"groupName":"divi/font-body"}},"content":{"innerContent":{"desktop":{"value":"\u003cp\u003eFließtext mit dem Gruppen-Preset „[Fixture] Fließtext“ direkt am Modul.\u003c/p\u003e"}}},"builderVersion":"5.2.1"} /-->
<!-- wp:divi/text {"module":{"meta":{"adminLabel":{"desktop":{"value":"Text mit String-Variable"}}}},"content":{"innerContent":{"desktop":{"value":"$variable({\u0022type\u0022:\u0022content\u0022,\u0022value\u0022:{\u0022name\u0022:\u0022gvid-7uckqqhmrh\u0022,\u0022settings\u0022:{}}})$"}}},"builderVersion":"5.2.1"} /-->
<!-- wp:divi/button {"module":{"meta":{"adminLabel":{"desktop":{"value":"Button mit Modul-Preset"}}}},"modulePreset":["3gbmxlurey"],"button":{"innerContent":{"desktop":{"value":{"text":"Angebot anfragen","linkUrl":"$variable({\u0022type\u0022:\u0022content\u0022,\u0022value\u0022:{\u0022name\u0022:\u0022gvid-nt8f6iz2qh\u0022,\u0022settings\u0022:{}}})$"}}}},"builderVersion":"5.2.1"} /-->
<!-- wp:divi/blurb {"module":{"meta":{"adminLabel":{"desktop":{"value":"Blurb mit Modul- und Gruppen-Preset"}}}},"modulePreset":["vdcl6msnuo"],"groupPreset":{"module.decoration.spacing":{"presetId":["apzj7e17ok"],"groupName":"divi/spacing"}},"title":{"innerContent":{"desktop":{"value":"Möbel nach Maß"}}},"content":{"innerContent":{"desktop":{"value":"\u003cp\u003eBlurb mit „[Fixture] Blurb Leistung“ und dem Gruppen-Preset „[Fixture] Abstand Karte“.\u003c/p\u003e"}}},"builderVersion":"5.2.1"} /-->
<!-- wp:divi/image {"module":{"meta":{"adminLabel":{"desktop":{"value":"Bild aus Bild-Variable"}}}},"image":{"innerContent":{"desktop":{"value":{"src":"$variable({\u0022type\u0022:\u0022content\u0022,\u0022value\u0022:{\u0022name\u0022:\u0022gvid-qmc3cy1alq\u0022,\u0022settings\u0022:{}}})$","alt":"Werkstatt"}}}},"builderVersion":"5.2.1"} /-->
<!-- wp:divi/divider {"module":{"meta":{"adminLabel":{"desktop":{"value":"Trenner ohne Preset (Standard-Preset)"}}}},"builderVersion":"5.2.1"} /-->
<!-- /wp:divi/column -->
<!-- /wp:divi/row -->
<!-- /wp:divi/section --><!-- /wp:divi/placeholder -->
@@ -0,0 +1,36 @@
{
"post": {
"ID": 3182,
"post_type": "page",
"post_status": "draft",
"post_title": "[Fixture] Designsystem",
"post_name": "",
"post_date_gmt": "0000-00-00 00:00:00",
"post_modified_gmt": "2026-09-27 22:21:39",
"content_file": "page--designsystem.html",
"content_sha256": "758485d1c95447ecae444e823a62eee1ce4d5e8525d13f607c0cdf4ab1ac207f"
},
"meta": {
"_et_pb_use_builder": [
"on"
],
"_et_pb_show_page_creation": [
"off"
],
"_et_pb_first_image": [
""
],
"_et_pb_truncate_post": [
""
],
"_et_pb_truncate_post_date": [
""
],
"_et_pb_use_divi_5": [
"on"
],
"et_enqueued_post_fonts": [
"a:3:{s:6:\"family\";a:2:{i:0;s:111:\"Merriweather:300,regular,500,600,700,800,900,300italic,italic,500italic,600italic,700italic,800italic,900italic\";i:1;s:94:\"Open+Sans:300,regular,500,600,700,800,300italic,italic,500italic,600italic,700italic,800italic\";}s:6:\"subset\";a:2:{i:0;s:5:\"latin\";i:1;s:9:\"latin-ext\";}s:9:\"cache_key\";s:74:\"{\"gph\":-1,\"divi\":\"5.2.1\",\"wp\":\"7.1.2\",\"enable_all_character_sets\":\"false\"}\";}"
]
}
}
@@ -0,0 +1,17 @@
{
"rows": [
{
"option_name": "et_divi_builder_presets_history_meta",
"autoload": "off",
"value": {
"index": -1,
"size": 0
}
}
],
"et_divi_flags": {
"presets_storage_migrated_flag": true,
"builder_global_presets_history_migrated": true,
"custom_defaults_migrated_flag": true
}
}
+909
View File
@@ -0,0 +1,909 @@
{
"option_name": "et_divi_builder_global_presets_d5",
"stored": {
"module": {
"divi/button": {
"default": "",
"items": {
"3gbmxlurey": {
"type": "module",
"id": "3gbmxlurey",
"name": "[Fixture] Button Primär",
"moduleName": "divi/button",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"button": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"font": {
"font": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$",
"weight": "600"
}
}
}
}
}
}
},
"styleAttrs": {
"button": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"font": {
"font": {
"desktop": {
"value": {
"weight": "600",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$"
}
}
}
}
}
}
}
}
}
},
"divi/text": {
"default": "",
"items": {
"hsiy1sjxt7": {
"type": "module",
"id": "hsiy1sjxt7",
"name": "[Fixture] Text Hinweis",
"moduleName": "divi/text",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"module": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"spacing": {
"desktop": {
"value": {
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
}
}
}
}
}
}
},
"styleAttrs": {
"module": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"spacing": {
"desktop": {
"value": {
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
}
}
}
}
}
}
},
"groupPresets": {
"content.decoration.bodyFont": {
"presetId": [
"ja6o54jtlc"
],
"groupName": "divi/font-body"
}
}
}
}
},
"divi/blurb": {
"default": "",
"items": {
"vdcl6msnuo": {
"type": "module",
"id": "vdcl6msnuo",
"name": "[Fixture] Blurb Leistung",
"moduleName": "divi/blurb",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"title": {
"decoration": {
"font": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$",
"weight": "700"
}
}
}
}
}
},
"module": {
"decoration": {
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
},
"styles": {
"all": {
"width": "2px",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-pgtgy2j1i7\",\"settings\":{}}})$",
"style": "solid"
}
}
}
}
}
}
}
},
"styleAttrs": {
"module": {
"decoration": {
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
},
"styles": {
"all": {
"width": "2px",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-pgtgy2j1i7\",\"settings\":{}}})$",
"style": "solid"
}
}
}
}
}
}
},
"title": {
"decoration": {
"font": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"weight": "700",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$"
}
}
}
}
}
}
}
}
}
},
"divi/divider": {
"default": "g7kvfq5uh8",
"items": {
"g7kvfq5uh8": {
"type": "module",
"id": "g7kvfq5uh8",
"name": "[Fixture] Trenner Standard",
"moduleName": "divi/divider",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"divider": {
"advanced": {
"line": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-989stx15zc\",\"settings\":{}}})$",
"weight": "3px"
}
}
}
}
}
},
"styleAttrs": {
"divider": {
"advanced": {
"line": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-989stx15zc\",\"settings\":{}}})$",
"weight": "3px"
}
}
}
}
}
}
}
}
}
},
"group": {
"divi/font-body": {
"default": "",
"items": {
"ja6o54jtlc": {
"type": "group",
"id": "ja6o54jtlc",
"name": "[Fixture] Fließtext",
"groupName": "divi/font-body",
"groupId": "content.decoration.bodyFont",
"moduleName": "divi/text",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"content": {
"decoration": {
"bodyFont": {
"body": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$",
"size": "17px",
"lineHeight": "1.8em"
}
}
}
}
}
}
}
},
"styleAttrs": {
"content": {
"decoration": {
"bodyFont": {
"body": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$",
"size": "17px",
"lineHeight": "1.8em"
}
}
}
}
}
}
}
}
}
}
},
"divi/spacing": {
"default": "",
"items": {
"apzj7e17ok": {
"type": "group",
"id": "apzj7e17ok",
"name": "[Fixture] Abstand Karte",
"groupName": "divi/spacing",
"groupId": "module.decoration.spacing",
"moduleName": "divi/blurb",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"module": {
"decoration": {
"spacing": {
"desktop": {
"value": {
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
},
"margin": {
"bottom": "24px"
}
}
}
}
}
}
},
"styleAttrs": {
"module": {
"decoration": {
"spacing": {
"desktop": {
"value": {
"margin": {
"bottom": "24px"
},
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
}
}
}
}
}
}
}
}
}
}
}
},
"get_data": {
"module": {
"divi/button": {
"default": "",
"items": {
"3gbmxlurey": {
"type": "module",
"id": "3gbmxlurey",
"name": "[Fixture] Button Primär",
"moduleName": "divi/button",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"button": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"font": {
"font": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$",
"weight": "600"
}
}
}
}
}
}
},
"styleAttrs": {
"button": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"font": {
"font": {
"desktop": {
"value": {
"weight": "600",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$"
}
}
}
}
}
}
}
}
}
},
"divi/text": {
"default": "",
"items": {
"hsiy1sjxt7": {
"type": "module",
"id": "hsiy1sjxt7",
"name": "[Fixture] Text Hinweis",
"moduleName": "divi/text",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"module": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"spacing": {
"desktop": {
"value": {
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
}
}
}
}
}
}
},
"styleAttrs": {
"module": {
"decoration": {
"background": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-gg4lef6xns\",\"settings\":{}}})$"
}
}
},
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
}
}
}
},
"spacing": {
"desktop": {
"value": {
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
}
}
}
}
}
}
},
"groupPresets": {
"content.decoration.bodyFont": {
"presetId": [
"ja6o54jtlc"
],
"groupName": "divi/font-body"
}
}
}
}
},
"divi/blurb": {
"default": "",
"items": {
"vdcl6msnuo": {
"type": "module",
"id": "vdcl6msnuo",
"name": "[Fixture] Blurb Leistung",
"moduleName": "divi/blurb",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"title": {
"decoration": {
"font": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$",
"weight": "700"
}
}
}
}
}
},
"module": {
"decoration": {
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
},
"styles": {
"all": {
"width": "2px",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-pgtgy2j1i7\",\"settings\":{}}})$",
"style": "solid"
}
}
}
}
}
}
}
},
"styleAttrs": {
"module": {
"decoration": {
"border": {
"desktop": {
"value": {
"radius": {
"sync": "on",
"topLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"topRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomLeft": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$",
"bottomRight": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-f6yq6mayfy\",\"settings\":{}}})$"
},
"styles": {
"all": {
"width": "2px",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-pgtgy2j1i7\",\"settings\":{}}})$",
"style": "solid"
}
}
}
}
}
}
},
"title": {
"decoration": {
"font": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"weight": "700",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$"
}
}
}
}
}
}
}
}
}
},
"divi/divider": {
"default": "g7kvfq5uh8",
"items": {
"g7kvfq5uh8": {
"type": "module",
"id": "g7kvfq5uh8",
"name": "[Fixture] Trenner Standard",
"moduleName": "divi/divider",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"divider": {
"advanced": {
"line": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-989stx15zc\",\"settings\":{}}})$",
"weight": "3px"
}
}
}
}
}
},
"styleAttrs": {
"divider": {
"advanced": {
"line": {
"desktop": {
"value": {
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-989stx15zc\",\"settings\":{}}})$",
"weight": "3px"
}
}
}
}
}
}
}
}
}
},
"group": {
"divi/font-body": {
"default": "",
"items": {
"ja6o54jtlc": {
"type": "group",
"id": "ja6o54jtlc",
"name": "[Fixture] Fließtext",
"groupName": "divi/font-body",
"groupId": "content.decoration.bodyFont",
"moduleName": "divi/text",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"content": {
"decoration": {
"bodyFont": {
"body": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$",
"size": "17px",
"lineHeight": "1.8em"
}
}
}
}
}
}
}
},
"styleAttrs": {
"content": {
"decoration": {
"bodyFont": {
"body": {
"font": {
"desktop": {
"value": {
"family": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-d4a5bsz2gt\",\"settings\":{}}})$",
"color": "$variable({\"type\":\"color\",\"value\":{\"name\":\"gcid-q9swzy97df\",\"settings\":{}}})$",
"size": "17px",
"lineHeight": "1.8em"
}
}
}
}
}
}
}
}
}
}
},
"divi/spacing": {
"default": "",
"items": {
"apzj7e17ok": {
"type": "group",
"id": "apzj7e17ok",
"name": "[Fixture] Abstand Karte",
"groupName": "divi/spacing",
"groupId": "module.decoration.spacing",
"moduleName": "divi/blurb",
"version": "5.2.1",
"created": 1790547699462,
"updated": 1790547699462,
"attrs": {
"module": {
"decoration": {
"spacing": {
"desktop": {
"value": {
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
},
"margin": {
"bottom": "24px"
}
}
}
}
}
}
},
"styleAttrs": {
"module": {
"decoration": {
"spacing": {
"desktop": {
"value": {
"margin": {
"bottom": "24px"
},
"padding": {
"top": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"right": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"bottom": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"left": "$variable({\"type\":\"content\",\"value\":{\"name\":\"gvid-5dec72fwsc\",\"settings\":{}}})$",
"syncVertical": "on",
"syncHorizontal": "on"
}
}
}
}
}
}
}
}
}
}
}
},
"legacy_d4_option": {
"option_name": "et_divi_builder_global_presets_ng",
"autoload": "off",
"option_value": "O:8:\"stdClass\":0:{}"
},
"is_legacy_presets_imported": ""
}
@@ -0,0 +1,191 @@
<?php
/**
* Exports the stage 4 design system fixtures from the local site into tests/Fixtures/divi/stage4/: global colors,
* global variables, presets (each as stored in the database and as Divi's getter returns it), the relevant et_divi
* subset, the (Divi 4) preset history options and the page "[Fixture] Designsystem" (post row, meta, post_content
* byte-exact). How the data was created: tests/Integration/divi-seed-stage4-design.php and
* tests/Fixtures/divi/stage4/README.md.
*
* Usage (DDEV, WordPress root):
* wp eval-file wp-content/plugins/WP-LIT-MCP/tests/Integration/divi-export-stage4-fixtures.php
*
* Read-only. Fixtures are committed – no personal data. No `declare(strict_types=1);` – wp eval-file uses eval().
*/
defined('WP_CLI') && WP_CLI || exit;
use ET\Builder\Packages\GlobalData\GlobalData;
use ET\Builder\Packages\GlobalData\GlobalPreset;
$lit_dir = dirname(__DIR__) . '/Fixtures/divi/stage4';
$lit_page_title = '[Fixture] Designsystem';
$lit_write = static function (string $file, string $data): void {
if (file_put_contents($file, $data) === false) {
WP_CLI::error('Cannot write ' . $file);
}
};
$lit_json = static fn ($data): string => wp_json_encode(
$data,
JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
) . "\n";
/** The option row exactly as stored (serialized string, autoload flag) – shows the PHP types Divi writes. */
$lit_raw_option = static function (string $name): ?array {
global $wpdb;
$row = $wpdb->get_row($wpdb->prepare(
"SELECT option_value, autoload FROM {$wpdb->options} WHERE option_name = %s",
$name
));
return $row === null ? null : ['option_name' => $name, 'autoload' => $row->autoload, 'option_value' => $row->option_value];
};
$lit_pages = get_posts([
'post_type' => 'page',
'post_status' => ['draft', 'publish', 'private', 'pending'],
'title' => $lit_page_title,
'numberposts' => 1,
'orderby' => 'ID',
'order' => 'ASC',
]);
if ($lit_pages === []) {
WP_CLI::error('Page "' . $lit_page_title . '" not found – run tests/Integration/divi-seed-stage4-design.php first.');
}
$lit_page = $lit_pages[0];
if (! is_dir($lit_dir) && ! wp_mkdir_p($lit_dir)) {
WP_CLI::error('Cannot create ' . $lit_dir);
}
// Global colors: et_divi['et_global_data'] as stored, plus GlobalData::get_global_colors() (customizer colors merged
// in front; their lastUpdated is generated on every read).
$lit_et_divi = get_option('et_divi', []);
$lit_write($lit_dir . '/global-colors.json', $lit_json([
'stored' => [
'option_name' => 'et_divi',
'key' => 'et_global_data',
'value' => maybe_unserialize($lit_et_divi['et_global_data'] ?? null),
],
'get_global_colors' => GlobalData::get_global_colors(),
]));
// Global variables: product option et_divi_global_variables (arrays), getter result (every type is a stdClass –
// an empty type therefore encodes as {} here, not []).
$lit_write($lit_dir . '/global-variables.json', $lit_json([
'stored' => get_option('et_divi_global_variables', null),
'stored_raw' => $lit_raw_option('et_divi_global_variables'),
'get_global_variables' => GlobalData::get_global_variables(),
'get_global_variables_php_types' => array_map(
static fn ($items) => get_debug_type($items),
GlobalData::get_global_variables()
),
]));
// Presets: product option et_divi_builder_global_presets_d5, plus the D4 legacy option and import flag.
$lit_write($lit_dir . '/presets.json', $lit_json([
'option_name' => 'et_divi_' . GlobalPreset::option_name(),
'stored' => get_option('et_divi_' . GlobalPreset::option_name(), null),
'get_data' => GlobalPreset::get_data(),
'legacy_d4_option' => $lit_raw_option('et_divi_builder_global_presets_ng'),
'is_legacy_presets_imported' => GlobalPreset::is_legacy_presets_imported(),
]));
// Preset history (Divi 4 storage; Divi 5 preset saves do not write it).
global $wpdb;
$lit_history_rows = $wpdb->get_results(
"SELECT option_name, option_value, autoload FROM {$wpdb->options}
WHERE option_name LIKE 'et\\_divi\\_builder\\_presets\\_history%'
OR option_name LIKE 'et\\_divi\\_builder\\_global\\_presets\\_history%'
OR option_name LIKE 'et\\_divi\\_builder\\_custom\\_defaults\\_history%'
ORDER BY option_name"
);
$lit_write($lit_dir . '/presets-history.json', $lit_json([
'rows' => array_map(static fn ($row) => [
'option_name' => $row->option_name,
'autoload' => $row->autoload,
'value' => maybe_unserialize($row->option_value),
], $lit_history_rows),
'et_divi_flags' => array_intersect_key((array) $lit_et_divi, array_flip([
'builder_global_presets_history_migrated',
'presets_storage_migrated_flag',
'custom_defaults_migrated_flag',
])),
]));
// Theme options relevant to spec §7 (whitelist): present keys with their stored value, absent keys listed.
$lit_keys = [
'heading_font', 'body_font', 'heading_font_weight', 'body_font_weight', 'primary_nav_font', 'secondary_nav_font',
'all_buttons_font', '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',
'accent_color', 'secondary_accent_color', 'header_color', 'font_color', 'link_color', 'divi_logo',
];
foreach (array_keys((array) $lit_et_divi) as $key) {
if (str_starts_with($key, 'all_buttons_') || str_starts_with($key, 'divi_seo_')) {
$lit_keys[] = $key;
}
}
$lit_keys = array_values(array_unique($lit_keys));
$lit_present = [];
$lit_absent = [];
foreach ($lit_keys as $key) {
if (array_key_exists($key, (array) $lit_et_divi)) {
$lit_present[$key] = $lit_et_divi[$key];
} else {
$lit_absent[] = $key;
}
}
$lit_write($lit_dir . '/et-divi-subset.json', $lit_json([
'option_name' => 'et_divi',
'present' => (object) $lit_present,
'absent' => $lit_absent,
'effective' => [
'accent_colors' => GlobalData::get_accent_color_values(),
'customizer_fonts' => GlobalData::get_customizer_fonts(),
],
]));
// The page: post row, all meta (raw), post_content byte-exact.
$lit_meta = [];
foreach ($wpdb->get_results($wpdb->prepare(
"SELECT meta_key, meta_value FROM {$wpdb->postmeta} WHERE post_id = %d ORDER BY meta_id",
$lit_page->ID
)) as $row) {
if (! in_array($row->meta_key, ['_edit_lock', '_edit_last'], true)) {
$lit_meta[$row->meta_key][] = $row->meta_value;
}
}
$lit_write($lit_dir . '/page--designsystem.json', $lit_json([
'post' => [
'ID' => $lit_page->ID,
'post_type' => $lit_page->post_type,
'post_status' => $lit_page->post_status,
'post_title' => $lit_page->post_title,
'post_name' => $lit_page->post_name,
'post_date_gmt' => $lit_page->post_date_gmt,
'post_modified_gmt' => $lit_page->post_modified_gmt,
'content_file' => 'page--designsystem.html',
'content_sha256' => hash('sha256', $lit_page->post_content),
],
'meta' => (object) $lit_meta,
]));
$lit_write($lit_dir . '/page--designsystem.html', $lit_page->post_content);
$lit_write($lit_dir . '/manifest.json', $lit_json([
'divi_version' => wp_get_theme('Divi')->get('Version'),
'builder_version' => ET_BUILDER_VERSION,
'files' => [
'global-colors.json',
'global-variables.json',
'presets.json',
'presets-history.json',
'et-divi-subset.json',
'page--designsystem.json',
'page--designsystem.html',
],
'posts' => ['page--designsystem' => $lit_page->ID],
]));
WP_CLI::success('Stage 4 fixtures exported to ' . $lit_dir);
@@ -0,0 +1,558 @@
<?php
/**
* Seeds realistic Divi 5 design data for the Etappe 4 fixtures (spec §15 "Format der Presets/Variablen an echten
* Daten verifizieren"): four global colors (one relative to another), one global variable per type, four module
* presets (one of them the default of its module) and two option group presets that reference colors and variables,
* plus the draft page "[Fixture] Designsystem" that uses them.
*
* Everything is written through the REST endpoints the Visual Builder itself calls, dispatched in-process with
* rest_do_request() – so Divi's own argument schema, sanitize callbacks, permission callbacks and save functions run:
* POST divi/v1/global-data/global-colors → GlobalDataController::update_global_colors → GlobalData::set_global_colors
* POST divi/v1/global-data/global-variables → GlobalDataController::update_global_variables → GlobalData::set_global_variables
* POST divi/v1/global-data/global-preset/sync → GlobalPresetController::sync → GlobalPreset::prepare_data/save_data
* POST divi/v1/sync-to-server → SyncToServerController::update (like "Entwurf speichern")
* Formats and sources: docs/superpowers/notes/2026-09-28-etappe-4-divi-formate.md.
*
* Usage (DDEV, WordPress root):
* wp eval-file wp-content/plugins/WP-LIT-MCP/tests/Integration/divi-seed-stage4-design.php
*
* Idempotent: entries are found again by their "[Fixture] …" label/name and updated in place (IDs, "created" and
* "lastUpdated" stay when nothing changed); nothing is duplicated. It never sends the five customizer colors
* (gcid-primary-color …) – their values in et_divi stay untouched – and never deletes anything.
* Runs as the first administrator when WP-CLI has no --user. No `declare(strict_types=1);` – wp eval-file uses eval().
*/
defined('WP_CLI') && WP_CLI || exit;
use ET\Builder\Framework\Controllers\RESTController;
use ET\Builder\Packages\Conversion\Conversion;
use ET\Builder\Packages\GlobalData\GlobalData;
use ET\Builder\Packages\GlobalData\GlobalPreset;
if (get_current_user_id() === 0) {
$lit_admins = get_users(['role' => 'administrator', 'number' => 1, 'orderby' => 'ID']);
if ($lit_admins === []) {
WP_CLI::error('No administrator found.');
}
wp_set_current_user($lit_admins[0]->ID);
}
if (! current_user_can('edit_theme_options') || ! et_pb_is_allowed('variables_manager')) {
WP_CLI::error('The current user needs edit_theme_options and Divi\'s role right "variables_manager".');
}
/** Random ID like the Visual Builder's generateNanoUuid(): 10 characters of [0-9a-z]. */
$lit_nano = static function (): string {
$alphabet = '0123456789abcdefghijklmnopqrstuvwxyz';
$id = '';
for ($i = 0; $i < 10; $i++) {
$id .= $alphabet[random_int(0, 35)];
}
return $id;
};
/**
* Dispatches a request to one of Divi's REST routes as the current user; stops on any error. Divi checks a per-route
* nonce in the X-ET-Nonce header (RESTRoute, action "divi/v1<route>--POST"), created here like the builder gets it.
*/
$lit_rest = static function (string $route, array $body): array {
$request = new WP_REST_Request('POST', '/divi/v1' . $route);
$request->set_header('Content-Type', 'application/json');
$request->set_header('X-ET-Nonce', RESTController::create_nonce('divi/v1', $route, 'POST'));
$request->set_body(wp_json_encode($body));
$response = rest_do_request($request);
$data = rest_get_server()->response_to_data($response, false);
if ($response->is_error() || $response->get_status() >= 300) {
WP_CLI::error(sprintf('%s → HTTP %d: %s', $route, $response->get_status(), wp_json_encode($data)));
}
return is_array($data) ? $data : (array) $data;
};
/** Dynamic reference to a global color, optionally with HSL/opacity adjustments (relative color). */
$lit_color_ref = static fn (string $id, array $settings = []): string => '$variable(' . wp_json_encode(
['type' => 'color', 'value' => ['name' => $id, 'settings' => (object) $settings]]
) . ')$';
/** Dynamic reference to a global variable (numbers, strings, images, links, fonts). */
$lit_var_ref = static fn (string $id): string => '$variable(' . wp_json_encode(
['type' => 'content', 'value' => ['name' => $id, 'settings' => (object) []]]
) . ')$';
$lit_now_iso = gmdate('Y-m-d\TH:i:s.v\Z');
$lit_now_ms = (int) round(microtime(true) * 1000);
// ---------------------------------------------------------------------------------------------------------------
// 1. Global colors
// ---------------------------------------------------------------------------------------------------------------
$lit_colors_before = GlobalData::get_global_colors();
$lit_color_id = static function (string $label) use ($lit_colors_before, $lit_nano): string {
foreach ($lit_colors_before as $id => $color) {
if (is_array($color) && ($color['label'] ?? '') === $label && ! isset(GlobalData::$customizer_colors[$id])) {
return (string) $id;
}
}
return 'gcid-' . $lit_nano();
};
$lit_c = [
'holz_dunkel' => $lit_color_id('[Fixture] Holz dunkel'),
'holz_hell' => $lit_color_id('[Fixture] Holz hell'),
'salbei' => $lit_color_id('[Fixture] Salbeigrün'),
'sand' => $lit_color_id('[Fixture] Sandbeige'),
];
$lit_color_specs = [
$lit_c['holz_dunkel'] => ['[Fixture] Holz dunkel', '#5b3a29'],
// Relative color: Holz dunkel, 30 % lighter – stored as a $variable() reference with HSL settings.
$lit_c['holz_hell'] => ['[Fixture] Holz hell', $lit_color_ref($lit_c['holz_dunkel'], ['lightness' => 30])],
$lit_c['salbei'] => ['[Fixture] Salbeigrün', '#7d9b76'],
$lit_c['sand'] => ['[Fixture] Sandbeige', '#efe6d8'],
];
$lit_colors_payload = [];
foreach ($lit_color_specs as $id => [$label, $value]) {
$old = $lit_colors_before[$id] ?? null;
$unchanged = is_array($old) && ($old['color'] ?? null) === $value && ($old['status'] ?? '') === 'active';
$lit_colors_payload[$id] = [
'color' => $value,
'folder' => '',
'label' => $label,
'lastUpdated' => $unchanged ? (string) $old['lastUpdated'] : $lit_now_iso,
'status' => 'active',
'usedInPosts' => is_array($old['usedInPosts'] ?? null) ? $old['usedInPosts'] : [],
];
}
// Only the fixture colors are sent: the endpoint merges (set_global_colors(…, true)), and leaving out the customizer
// colors keeps accent_color & co. in et_divi untouched.
$lit_rest('/global-data/global-colors', ['global_colors' => $lit_colors_payload]);
WP_CLI::log('Colors: ' . implode(', ', array_map(
static fn ($id, $spec) => $spec[0] . ' = ' . $id,
array_keys($lit_color_specs),
$lit_color_specs
)));
// ---------------------------------------------------------------------------------------------------------------
// 2. Global variables – the endpoint REPLACES the whole option, so the full current set is sent.
// ---------------------------------------------------------------------------------------------------------------
$lit_vars = [];
foreach (GlobalData::get_global_variables() as $type => $items) {
if (! in_array($type, ['numbers', 'strings', 'images', 'links', 'fonts'], true)) {
continue; // "colors" is never stored in global_variables (sanitize_global_variables_data drops it).
}
foreach ((array) $items as $id => $item) {
if ($type === 'fonts' && isset(GlobalData::$customizer_fonts[$id])) {
continue; // Customizer fonts come from et_divi heading_font/body_font, not from this option.
}
unset($item['allowedActions']);
$lit_vars[$type][$id] = $item;
}
}
$lit_var_id = static function (string $type, string $label) use (&$lit_vars, $lit_nano): string {
foreach ($lit_vars[$type] ?? [] as $id => $item) {
if (($item['label'] ?? '') === $label) {
return (string) $id;
}
}
return 'gvid-' . $lit_nano();
};
$lit_image = get_posts(['post_type' => 'attachment', 'post_mime_type' => 'image', 'numberposts' => 1, 'orderby' => 'ID', 'order' => 'ASC']);
$lit_image_url = $lit_image !== [] ? (string) wp_get_attachment_url($lit_image[0]->ID) : get_template_directory_uri() . '/images/logo.png';
$lit_var_specs = [
'numbers' => [
'eckenradius' => ['[Fixture] Eckenradius', '8px'],
'abstand' => ['[Fixture] Abstand Karte', 'clamp(1.5rem, 4vw, 2.5rem)'],
],
'strings' => ['slogan' => ['[Fixture] Slogan', 'Handwerk aus Meisterhand – seit 1987']],
'images' => ['werkstatt' => ['[Fixture] Werkstattbild', $lit_image_url]],
'links' => ['kontakt' => ['[Fixture] Kontaktseite', home_url('/kontakt/')]],
'fonts' => ['akzent' => ['[Fixture] Akzentschrift', 'Merriweather']],
];
$lit_v = [];
foreach ($lit_var_specs as $type => $specs) {
foreach ($specs as $key => [$label, $value]) {
$id = $lit_var_id($type, $label);
$lit_v[$key] = $id;
$old = $lit_vars[$type][$id] ?? null;
$unchanged = is_array($old) && (string) ($old['value'] ?? '') === $value && ($old['status'] ?? '') === 'active';
$order = is_array($old) && isset($old['order'])
? (int) $old['order']
: 1 + count(array_filter($lit_vars[$type] ?? [], static fn ($i) => ($i['status'] ?? '') === 'active'));
$lit_vars[$type][$id] = [
'id' => $id,
'label' => $label,
'value' => $value,
'order' => $order,
'status' => 'active',
'lastUpdated' => $unchanged && isset($old['lastUpdated']) ? (string) $old['lastUpdated'] : $lit_now_iso,
'variableType' => $type,
];
}
}
$lit_rest('/global-data/global-variables', ['global_variables' => $lit_vars]);
WP_CLI::log('Variables: ' . wp_json_encode($lit_v));
// ---------------------------------------------------------------------------------------------------------------
// 3. Presets – the sync endpoint REPLACES the whole option; it refuses a payload with fewer presets than stored.
// ---------------------------------------------------------------------------------------------------------------
$lit_presets = GlobalPreset::get_data();
$lit_find_preset = static function (string $kind, string $sub, string $name) use ($lit_presets): ?array {
foreach ($lit_presets[$kind][$sub]['items'] ?? [] as $item) {
if (is_array($item) && ($item['name'] ?? '') === $name) {
return $item;
}
}
return null;
};
/** Splits preset attrs into styleAttrs / renderAttrs with Divi's own attribute map (Conversion, D4→D5 preset path). */
$lit_split = static function (string $moduleName, array $attrs): array {
$map = Conversion::get_preset_attrs_mapping($moduleName);
return [
Conversion::get_preset_attrs($attrs, ['style'], $map),
Conversion::get_preset_attrs($attrs, ['html', 'script'], $map),
];
};
/** Builds one preset item like the Visual Builder's generateNewPreset / generateNewOptionGroupPreset. */
$lit_preset = static function (string $kind, string $sub, array $spec) use ($lit_find_preset, $lit_split, $lit_nano, $lit_now_ms): array {
$old = $lit_find_preset($kind, $sub, $spec['name']);
[$styleAttrs, $renderAttrs] = $lit_split($spec['moduleName'], $spec['attrs']);
$item = ['type' => $kind, 'id' => $old['id'] ?? $lit_nano(), 'name' => $spec['name']];
if ($kind === 'group') {
$item += ['groupName' => $sub, 'groupId' => $spec['groupId']];
}
$item += [
'moduleName' => $spec['moduleName'],
'version' => ET_BUILDER_VERSION,
'created' => (int) ($old['created'] ?? $lit_now_ms),
'updated' => (int) ($old['updated'] ?? $lit_now_ms),
'attrs' => $spec['attrs'],
];
if ($styleAttrs !== []) {
$item['styleAttrs'] = $styleAttrs;
}
if ($renderAttrs !== []) {
$item['renderAttrs'] = $renderAttrs;
}
if (! empty($spec['groupPresets'])) {
$item['groupPresets'] = $spec['groupPresets'];
}
if ($old !== null) {
$compare = static function (array $preset): string {
unset($preset['updated'], $preset['priority'], $preset['order']);
ksort($preset);
return wp_json_encode($preset);
};
if ($compare($item) !== $compare($old)) {
$item['updated'] = $lit_now_ms;
}
foreach (['priority', 'order'] as $key) {
if (isset($old[$key])) {
$item[$key] = $old[$key];
}
}
}
return $item;
};
$lit_radius = static fn (string $value): array => [
'sync' => 'on',
'topLeft' => $value,
'topRight' => $value,
'bottomLeft' => $value,
'bottomRight' => $value,
];
$lit_padding = static fn (string $value): array => [
'top' => $value,
'right' => $value,
'bottom' => $value,
'left' => $value,
'syncVertical' => 'on',
'syncHorizontal' => 'on',
];
// Option group presets first – the text module preset nests the body-font preset.
$lit_group_font = $lit_preset('group', 'divi/font-body', [
'name' => '[Fixture] Fließtext',
'moduleName' => 'divi/text',
'groupId' => 'content.decoration.bodyFont',
'attrs' => ['content' => ['decoration' => ['bodyFont' => ['body' => ['font' => ['desktop' => ['value' => [
'family' => $lit_var_ref($lit_v['akzent']),
'color' => $lit_color_ref($lit_c['holz_dunkel']),
'size' => '17px',
'lineHeight' => '1.8em',
]]]]]]]],
]);
$lit_group_spacing = $lit_preset('group', 'divi/spacing', [
'name' => '[Fixture] Abstand Karte',
'moduleName' => 'divi/blurb',
'groupId' => 'module.decoration.spacing',
'attrs' => ['module' => ['decoration' => ['spacing' => ['desktop' => ['value' => [
'padding' => $lit_padding($lit_var_ref($lit_v['abstand'])),
'margin' => ['bottom' => '24px'],
]]]]]],
]);
$lit_module_button = $lit_preset('module', 'divi/button', [
'name' => '[Fixture] Button Primär',
'moduleName' => 'divi/button',
'attrs' => ['button' => ['decoration' => [
'background' => ['desktop' => ['value' => ['color' => $lit_color_ref($lit_c['holz_dunkel'])]]],
'border' => ['desktop' => ['value' => ['radius' => $lit_radius($lit_var_ref($lit_v['eckenradius']))]]],
'font' => ['font' => ['desktop' => ['value' => [
'color' => $lit_color_ref($lit_c['sand']),
'weight' => '600',
]]]],
]]],
]);
$lit_module_text = $lit_preset('module', 'divi/text', [
'name' => '[Fixture] Text Hinweis',
'moduleName' => 'divi/text',
'attrs' => ['module' => ['decoration' => [
'background' => ['desktop' => ['value' => ['color' => $lit_color_ref($lit_c['sand'])]]],
'border' => ['desktop' => ['value' => ['radius' => $lit_radius($lit_var_ref($lit_v['eckenradius']))]]],
'spacing' => ['desktop' => ['value' => ['padding' => $lit_padding($lit_var_ref($lit_v['abstand']))]]],
]]],
'groupPresets' => [
'content.decoration.bodyFont' => ['presetId' => [$lit_group_font['id']], 'groupName' => 'divi/font-body'],
],
]);
$lit_module_blurb = $lit_preset('module', 'divi/blurb', [
'name' => '[Fixture] Blurb Leistung',
'moduleName' => 'divi/blurb',
'attrs' => [
'title' => ['decoration' => ['font' => ['font' => ['desktop' => ['value' => [
'family' => $lit_var_ref($lit_v['akzent']),
'color' => $lit_color_ref($lit_c['holz_dunkel']),
'weight' => '700',
]]]]]],
'module' => ['decoration' => ['border' => ['desktop' => ['value' => [
'radius' => $lit_radius($lit_var_ref($lit_v['eckenradius'])),
'styles' => ['all' => ['width' => '2px', 'color' => $lit_color_ref($lit_c['salbei']), 'style' => 'solid']],
]]]]],
],
]);
// Default preset of divi/divider – a module no other page of this site uses, so the default changes nothing else.
$lit_module_divider = $lit_preset('module', 'divi/divider', [
'name' => '[Fixture] Trenner Standard',
'moduleName' => 'divi/divider',
'attrs' => ['divider' => ['advanced' => ['line' => ['desktop' => ['value' => [
'color' => $lit_color_ref($lit_c['holz_hell']),
'weight' => '3px',
]]]]]],
]);
$lit_mine = [
'module' => [
'divi/button' => [$lit_module_button],
'divi/text' => [$lit_module_text],
'divi/blurb' => [$lit_module_blurb],
'divi/divider' => [$lit_module_divider],
],
'group' => [
'divi/font-body' => [$lit_group_font],
'divi/spacing' => [$lit_group_spacing],
],
];
$lit_defaults = ['module' => ['divi/divider' => $lit_module_divider['id']], 'group' => []];
// Stored format (option) → REST schema format (list of {default, items: list}), merged with our items.
$lit_payload = ['module' => [], 'group' => []];
foreach (['module', 'group'] as $kind) {
$subs = array_unique(array_merge(array_keys($lit_presets[$kind] ?? []), array_keys($lit_mine[$kind])));
foreach ($subs as $sub) {
$items = $lit_presets[$kind][$sub]['items'] ?? [];
foreach ($lit_mine[$kind][$sub] ?? [] as $item) {
$items[$item['id']] = $item;
}
$lit_payload[$kind][] = [
'default' => (string) ($lit_defaults[$kind][$sub] ?? ($lit_presets[$kind][$sub]['default'] ?? '')),
'items' => array_values($items),
];
}
}
$lit_rest('/global-data/global-preset/sync', ['presets' => $lit_payload, 'actionType' => 'ADD_NEW_MODULE_PRESET']);
WP_CLI::log('Presets: ' . wp_json_encode([
'button' => $lit_module_button['id'],
'text' => $lit_module_text['id'],
'blurb' => $lit_module_blurb['id'],
'divider (default)' => $lit_module_divider['id'],
'font-body' => $lit_group_font['id'],
'spacing' => $lit_group_spacing['id'],
]));
// ---------------------------------------------------------------------------------------------------------------
// 4. Page "[Fixture] Designsystem" (draft) with preset and variable references, saved like the builder's draft save.
// ---------------------------------------------------------------------------------------------------------------
$lit_block = static function (string $name, array $attrs, array $inner = []): string {
$attrs['builderVersion'] = ET_BUILDER_VERSION;
$json = serialize_block_attributes($attrs);
if ($inner === []) {
return "<!-- wp:{$name} {$json} /-->\n";
}
return "<!-- wp:{$name} {$json} -->\n" . implode('', $inner) . "<!-- /wp:{$name} -->\n";
};
$lit_label = static fn (string $label): array => ['meta' => ['adminLabel' => ['desktop' => ['value' => $label]]]];
$lit_text = static fn (string $html): array => ['innerContent' => ['desktop' => ['value' => $html]]];
$lit_modules = [
$lit_block('divi/heading', [
'module' => $lit_label('Überschrift'),
'title' => ['innerContent' => ['desktop' => ['value' => 'Designsystem-Fixture']]],
]),
$lit_block('divi/text', [
'module' => $lit_label('Text mit Modul-Preset'),
'modulePreset' => [$lit_module_text['id']],
'content' => $lit_text('<p>Hinweis-Text mit dem Modul-Preset „[Fixture] Text Hinweis“ (enthält das Gruppen-Preset „[Fixture] Fließtext“).</p>'),
]),
$lit_block('divi/text', [
'module' => $lit_label('Text mit Gruppen-Preset'),
'groupPreset' => ['content.decoration.bodyFont' => ['presetId' => [$lit_group_font['id']], 'groupName' => 'divi/font-body']],
'content' => $lit_text('<p>Fließtext mit dem Gruppen-Preset „[Fixture] Fließtext“ direkt am Modul.</p>'),
]),
$lit_block('divi/text', [
'module' => $lit_label('Text mit String-Variable'),
'content' => $lit_text($lit_var_ref($lit_v['slogan'])),
]),
$lit_block('divi/button', [
'module' => $lit_label('Button mit Modul-Preset'),
'modulePreset' => [$lit_module_button['id']],
'button' => ['innerContent' => ['desktop' => ['value' => [
'text' => 'Angebot anfragen',
'linkUrl' => $lit_var_ref($lit_v['kontakt']),
]]]],
]),
$lit_block('divi/blurb', [
'module' => $lit_label('Blurb mit Modul- und Gruppen-Preset'),
'modulePreset' => [$lit_module_blurb['id']],
'groupPreset' => ['module.decoration.spacing' => ['presetId' => [$lit_group_spacing['id']], 'groupName' => 'divi/spacing']],
'title' => $lit_text('Möbel nach Maß'),
'content' => $lit_text('<p>Blurb mit „[Fixture] Blurb Leistung“ und dem Gruppen-Preset „[Fixture] Abstand Karte“.</p>'),
]),
$lit_block('divi/image', [
'module' => $lit_label('Bild aus Bild-Variable'),
'image' => ['innerContent' => ['desktop' => ['value' => [
'src' => $lit_var_ref($lit_v['werkstatt']),
'alt' => 'Werkstatt',
]]]],
]),
$lit_block('divi/divider', [
'module' => $lit_label('Trenner ohne Preset (Standard-Preset)'),
]),
];
$lit_column = $lit_block('divi/column', [
'module' => ['decoration' => ['sizing' => ['desktop' => ['value' => ['flexType' => '24_24']]]]],
], $lit_modules);
$lit_row = $lit_block('divi/row', ['module' => $lit_label('Designsystem Zeile')], [$lit_column]);
$lit_section = $lit_block('divi/section', ['module' => $lit_label('Designsystem Abschnitt')], [$lit_row]);
$lit_content = '<!-- wp:divi/placeholder -->' . rtrim($lit_section, "\n") . '<!-- /wp:divi/placeholder -->';
$lit_page_title = '[Fixture] Designsystem';
$lit_existing = get_posts([
'post_type' => 'page',
'post_status' => ['draft', 'publish', 'private', 'pending'],
'title' => $lit_page_title,
'numberposts' => 1,
'orderby' => 'ID',
'order' => 'ASC',
]);
if ($lit_existing !== []) {
$lit_page_id = $lit_existing[0]->ID;
} else {
$lit_page_id = wp_insert_post([
'post_type' => 'page',
'post_status' => 'draft',
'post_title' => $lit_page_title,
'post_content' => '',
], true);
if (is_wp_error($lit_page_id)) {
WP_CLI::error($lit_page_id->get_error_message());
}
et_builder_enable_for_post($lit_page_id);
}
if (get_post_field('post_content', $lit_page_id) !== $lit_content) {
$lit_rest('/sync-to-server', [
'post_id' => $lit_page_id,
'post_status' => get_post_status($lit_page_id),
'syncType' => 'draft',
'content' => ['post_content' => $lit_content],
]);
}
WP_CLI::log('Page: ' . $lit_page_id);
// ---------------------------------------------------------------------------------------------------------------
// 5. Read back through Divi and through the plugin's DesignSystemReader.
// ---------------------------------------------------------------------------------------------------------------
$lit_colors_after = GlobalData::get_global_colors();
foreach ($lit_color_specs as $id => [$label, $value]) {
if (($lit_colors_after[$id]['color'] ?? null) !== $value || ($lit_colors_after[$id]['label'] ?? null) !== $label) {
WP_CLI::error("Color {$id} did not read back.");
}
}
$lit_vars_after = GlobalData::get_global_variables();
foreach ($lit_var_specs as $type => $specs) {
foreach ($specs as $key => [$label, $value]) {
$item = ((array) ($lit_vars_after[$type] ?? []))[$lit_v[$key]] ?? null;
if (! is_array($item) || $item['value'] !== $value || $item['label'] !== $label) {
WP_CLI::error("Variable {$lit_v[$key]} ({$type}) did not read back.");
}
}
}
$lit_presets_after = GlobalPreset::get_data();
foreach ($lit_mine as $kind => $subs) {
foreach ($subs as $sub => $items) {
foreach ($items as $item) {
if (($lit_presets_after[$kind][$sub]['items'][$item['id']]['name'] ?? null) !== $item['name']) {
WP_CLI::error("Preset {$item['id']} ({$kind} {$sub}) did not read back.");
}
}
}
}
if (($lit_presets_after['module']['divi/divider']['default'] ?? '') !== $lit_module_divider['id']) {
WP_CLI::error('The divider default preset did not read back.');
}
if (class_exists(\LIT\MCP\Integrations\Divi\Design\DesignSystemReader::class)) {
$lit_ds = (new \LIT\MCP\Integrations\Divi\Design\DesignSystemReader())->read();
$lit_labels = array_column($lit_ds->colors(), 'label');
$lit_var_labels = array_column($lit_ds->variables(), 'label');
$lit_preset_names = array_values($lit_ds->presetNames());
foreach (array_column($lit_color_specs, 0) as $label) {
in_array($label, $lit_labels, true) || WP_CLI::error("DesignSystemReader misses color {$label}.");
}
foreach ($lit_var_specs as $specs) {
foreach ($specs as [$label]) {
in_array($label, $lit_var_labels, true) || WP_CLI::error("DesignSystemReader misses variable {$label}.");
}
}
foreach ($lit_mine as $subs) {
foreach ($subs as $items) {
foreach ($items as $item) {
in_array($item['name'], $lit_preset_names, true) || WP_CLI::error("DesignSystemReader misses preset {$item['name']}.");
}
}
}
WP_CLI::log(sprintf(
'DesignSystemReader: %d colors, %d variables, %d presets, fonts %s',
count($lit_ds->colors()),
count($lit_ds->variables()),
count($lit_ds->presets()),
wp_json_encode($lit_ds->fonts())
));
} else {
WP_CLI::warning('DesignSystemReader not loaded (plugin inactive?) – skipped.');
}
WP_CLI::success('Stage 4 design data seeded; page ' . $lit_page_id . '.');