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:
@@ -0,0 +1,198 @@
|
|||||||
|
# Etappe 4 – Datenformate des Divi-Designsystems (Divi 5.2.1)
|
||||||
|
|
||||||
|
Stand 2026-09-28. Grundlage: Quelltext von Divi 5.2.1 und echte Daten, die über Divis eigene Speicherwege angelegt wurden (Seed-Skript `tests/Integration/divi-seed-stage4-design.php`, Fixtures `tests/Fixtures/divi/stage4/`). Erfüllt Spec §14 („Datenformate Designsystem nur aus Code abgeleitet“) und §15 („Format der Presets/Variablen an echten Daten verifizieren“).
|
||||||
|
|
||||||
|
Pfadangaben relativ zu `wp-content/themes/Divi/`. Abkürzung **B5** = `includes/builder-5/server/`. Minifizierte Builder-Dateien liegen in `includes/builder-5/visual-builder/build/`; dort steht statt einer Zeile ein Suchbegriff.
|
||||||
|
|
||||||
|
## 0. Grundlagen: wo Divi speichert
|
||||||
|
|
||||||
|
`et_get_option()`/`et_update_option()` (`epanel/custom_functions.php:211`, `:272`) haben drei Ziele:
|
||||||
|
|
||||||
|
- normale Theme-Option → Schlüssel im Array der Option **`et_divi`** (autoload);
|
||||||
|
- „Product Setting“ (letzter Parameter `true`) → **eigene Option `et_divi_<name>`**, autoload aus (`:224`, `:288-292`);
|
||||||
|
- `et_delete_option()` (`:316`) kennt **keine** Product Settings und löscht immer nur den Schlüssel in `et_divi`.
|
||||||
|
|
||||||
|
Folge: `GlobalPreset::delete_data()` (B5 `Packages/GlobalData/GlobalPreset.php:149-158`) ruft `et_delete_option(option_name())` auf und entfernt die Option `et_divi_builder_global_presets_d5` **nicht** – nur den statischen Cache. Für Etappe 4 nicht verwenden.
|
||||||
|
|
||||||
|
`et_update_option()` aktualisiert zusätzlich das globale `$et_theme_options`; direktes `update_option('et_divi', …)` lässt diesen Cache im selben Request veralten.
|
||||||
|
|
||||||
|
## 1. Globale Farben
|
||||||
|
|
||||||
|
**Speicherort:** `et_divi['et_global_data']['global_colors']` (normale Theme-Option, kein Product Setting). Die fünf Customizer-Farben liegen **nicht** dort, sondern als `et_divi['accent_color']`, `secondary_accent_color`, `header_color`, `font_color`, `link_color` (Zuordnung `GlobalData::$customizer_colors`, B5 `Packages/GlobalData/GlobalData.php:58-83`).
|
||||||
|
|
||||||
|
**Format eines Eintrags** (Schlüssel = ID):
|
||||||
|
|
||||||
|
```json
|
||||||
|
"gcid-q9swzy97df": {
|
||||||
|
"color": "#5b3a29",
|
||||||
|
"folder": "",
|
||||||
|
"label": "[Fixture] Holz dunkel",
|
||||||
|
"lastUpdated": "2026-09-27T22:21:39.000Z",
|
||||||
|
"status": "active",
|
||||||
|
"usedInPosts": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- ID: `gcid-` + 10 Zeichen `[0-9a-z]` (Builder: `generateVariableId`/`generateNanoUuid`, `global-data.js`, Suche ``S=(e,t)=>e||("colors"===t?`gcid-${_()}``). Ältere Daten können UUIDs haben (`gcid-79d0acb1-…`, Beispiele `GlobalData.php:700-770`). Prüfung serverseitig nur `substr($id, 0, 5) === 'gcid-'` (`:597-603`).
|
||||||
|
- `status`: `active` | `inactive` | `temporary`. Der Builder **löscht nie**: „Löschen“ setzt `status: inactive` (`global-data.js`, Suche `case"DELETE_GLOBAL_COLOR"`).
|
||||||
|
- `label`/`folder` werden gespeichert, obwohl der Konverter-Kommentar „not until D6“ sagt (`:159-160`); der Builder liest `label` (Suche `label:t.label||""`).
|
||||||
|
- `lastUpdated`: Format `Y-m-d\TH:i:s.v\Z`.
|
||||||
|
- **Relative Farbe** (Farbe aus anderer Farbe): `color` enthält eine Referenz
|
||||||
|
`$variable({"type":"color","value":{"name":"gcid-q9swzy97df","settings":{"lightness":30}}})$`
|
||||||
|
mit `settings` aus `hue`, `saturation`, `lightness`, `opacity` (`GlobalData::transform_state_into_global_color_value`, `:181-206`). CSS-Ausgabe: `--gcid-989stx15zc: hsl(from var(--gcid-q9swzy97df) calc(h + 0) calc(s + 0) calc(l + 30));` (`FrontEnd/Module/Style.php:910-947` über `StyleLibrary/Utils/Utils.php:86-130`). Abhängigkeiten werden rekursiv aufgelöst (`GlobalData.php:220-310`, Tiefe max. 10 in `:1336ff`).
|
||||||
|
|
||||||
|
**Lesen:** `GlobalData::get_global_colors()` (`:333-354`) liefert Customizer-Farben (neu erzeugt, `folder: customizer`, übersetztes Label, `lastUpdated` = jetzt, `:370-398`) **vor** den gespeicherten Farben; gleichnamige gespeicherte Customizer-IDs werden verworfen. Ergebnis wird statisch gecacht (`$_cached_data`), `set_global_colors()` setzt den Cache zurück, `get_customizer_colors()` hat einen eigenen `static`-Cache ohne Reset.
|
||||||
|
|
||||||
|
**Schreiben:** `GlobalData::set_global_colors(array $data, $already_sanitized = false)` (`:650-691`):
|
||||||
|
|
||||||
|
1. ohne `$already_sanitized`: `sanitize_global_colors_data()` (`:585-616`) – verwirft Einträge ohne `color` oder ohne `gcid-`, wendet `sanitize_text_field` auf jeden skalaren Wert an; `usedInPosts` wird mit `array_map` behandelt und **muss ein Array sein** (sonst `TypeError`).
|
||||||
|
2. Customizer-IDs im Payload → `et_update_option(<option_name>, color)` und aus dem Payload entfernt (`:664-674`).
|
||||||
|
3. **`$already_sanitized = false` ersetzt alle gespeicherten Farben, `true` mischt** (`array_merge`) mit den vorhandenen (`:678-684`).
|
||||||
|
4. `et_update_option('et_global_data', …)`, dann `ET_Core_PageResource::remove_static_resources('all', 'all', true)` (`:687-690`).
|
||||||
|
|
||||||
|
**Builder-Speicherweg:** `POST divi/v1/global-data/global-colors` (`VisualBuilder/REST/RESTRegistration.php:1001-1008`) → Schema-Sanitize `sanitize_global_colors_data` (`GlobalDataController.php:100-108`) → `set_global_colors($colors, true)` (`:71-78`), also **Mischen**. Der Builder schickt dabei die komplette Farbliste **einschließlich der fünf Customizer-Farben** (`global-data.js`, Suche `restRoute:"/divi/v1/global-data/global-colors"`); Entfernen einer Farbe ist über diesen Weg nicht möglich.
|
||||||
|
|
||||||
|
**Seiteneffekte:**
|
||||||
|
- Customizer-Sync ist direkt eingebaut (Schritt 2); ein separater Hook existiert nur für Divi 4 (`includes/builder/functions.php:13205-13237`, `et_global_colors_saved`, mit veralteten IDs `gcid-header-color`/`gcid-font-color`).
|
||||||
|
- `usedInPosts` pflegt nur der Builder im Browser (`UPDATE_GLOBAL_COLORS_USED_IN_POSTS`); serverseitig wird es nie berechnet. Über PHP angelegte Farben behalten `[]`.
|
||||||
|
- Einmalige Migration Divi 4 → 5 (`maybe_convert_global_colors_data`, `:526-551`) läuft beim Laden der Builder-Einstellungen (`Framework/Settings/Settings.php:159-162`).
|
||||||
|
|
||||||
|
**Rechte:** REST-Route nur `current_user_can('edit_posts')` (`GlobalDataController.php:124-130`); `set_global_colors()` selbst prüft nichts. Zusätzlich verlangt jede Divi-REST-Route den Nonce `X-ET-Nonce` für die Aktion `/divi/v1/<route>--POST` (`Framework/Route/RESTRoute.php:98`, `Framework/Controllers/RESTController.php:158-178`).
|
||||||
|
|
||||||
|
## 2. Globale Variablen
|
||||||
|
|
||||||
|
**Speicherort:** Product Setting **`et_divi_global_variables`** (eigene Option, autoload aus), gespeichert mit `et_update_option('global_variables', $data, false, '', '', true)` (`GlobalData.php:1016`).
|
||||||
|
|
||||||
|
**Gespeichertes Format** (PHP-Arrays):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"numbers": { "gvid-f6yq6mayfy": { "id": "gvid-f6yq6mayfy", "label": "[Fixture] Eckenradius", "value": "8px",
|
||||||
|
"order": "1", "status": "active", "lastUpdated": "…", "variableType": "numbers" } },
|
||||||
|
"strings": { … }, "images": { … }, "links": { … }, "fonts": { … }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Typen: nur `numbers`, `strings`, `images`, `links`, `fonts` (`sanitize_global_variables_data`, `:804-850`). **`colors` wird beim Speichern verworfen** – „Farb-Variablen“ im Variablen-Manager sind die globalen Farben aus Abschnitt 1.
|
||||||
|
- ID: `gvid-` + 10 Zeichen `[0-9a-z]`; Pflicht: `gvid-`-Präfix und nicht-leeres `label`.
|
||||||
|
- **Das Feld `id` im Eintrag ist nötig:** die CSS-Ausgabe benutzt `$value['id']`, nicht den Schlüssel (`FrontEnd/Module/Style.php:1002`).
|
||||||
|
- Sanitize: `value` bei `strings` zeichengetreu (`wp_check_invalid_utf8` + `wp_kses_no_null`), bei `links` `esc_url_raw`, sonst `sanitize_text_field` – dadurch wird `order` zum String (`"1"`). `allowedActions` wird verworfen. Der Builder speichert außerdem `lastUpdated` und `variableType` mit (`global-data.js`, Suche `case"ADD_GLOBAL_VARIABLE"`).
|
||||||
|
- `status`: `active` | `archived`. Builder-„Löschen“ setzt `archived` und `order: null` (Suche `case"DELETE_GLOBAL_VARIABLE"`), echtes Entfernen nur ohne Label/Wert.
|
||||||
|
- `numbers` erlaubt beliebige CSS-Ausdrücke (`clamp(1.5rem, 4vw, 2.5rem)` bleibt erhalten).
|
||||||
|
|
||||||
|
**Lesen:** `GlobalData::get_global_variables()` (`:896-963`) liefert ein Array, **jede Gruppe als `stdClass`** (`(object) $items`, `:959-962`), die Einträge darin als Arrays; ergänzt `allowedActions` und stellt die Customizer-Schriften `--et_global_heading_font` / `--et_global_body_font` (aus `et_divi['heading_font']`/`['body_font']`, Standard „Open Sans“, `:93-104`, `:415-437`) an den Anfang von `fonts`. Leere Gruppen sind leere `stdClass` (JSON `{}`). Eine beschädigte `fonts`-Gruppe wird still auf `[]` gesetzt (`:925`).
|
||||||
|
|
||||||
|
**Schreiben:** `GlobalData::set_global_variables(array $data)` (`:1002-1020`) **ersetzt die komplette Option**. Vorher also vollständig lesen, `stdClass` → Array wandeln, `allowedActions` und die beiden Customizer-Schriften herausnehmen (sonst landen sie in der Option), dann schreiben. `import_global_variables()` (`:1087-1137`) mischt, arbeitet aber mit `stdClass`-Gruppen und schreibt nur `id/label/value/status`.
|
||||||
|
Danach `remove_static_resources('all', 'all', true)`.
|
||||||
|
|
||||||
|
**Rechte:** `set_global_variables()` prüft `current_user_can('edit_theme_options') && et_pb_is_allowed('variables_manager')` und **kehrt sonst ohne Fehler zurück** (`:1003-1005`). Die REST-Route prüft nur `edit_posts` (`GlobalDataController.php:350-356`) und meldet danach Erfolg mit den unveränderten Daten – ein stiller Fehlschlag. `variables_manager` ist ein Recht des Divi-Rollen-Editors (`includes/builder/functions.php:9219-9222`, Auswertung `includes/builder/core.php:1128ff`, Option `et_pb_role_settings`; ohne Eintrag gilt „an“).
|
||||||
|
|
||||||
|
**Referenzen in Modulen und Presets:** `$variable({"type":"content","value":{"name":"gvid-…","settings":{}}})$` – für Zahlen/Schriften wird daraus `var(--gvid-…)` (`StyleLibrary/Utils/Utils.php:86-130`), für Strings/Links/Bilder der Wert beim Rendern (Dynamic Content, `Packages/Module/Layout/Components/DynamicContent/DynamicContentGlobalVariableOptions.php`). `:root` enthält nur `numbers` und `fonts` (`Style.php:991-1030`), Schriftwerte in Anführungszeichen. In `post_content` ist `"` innerhalb der Referenz als `"` kodiert (WordPress-Block-Serialisierung).
|
||||||
|
|
||||||
|
**Schriften der Customizer-Seite** schreibt der Builder separat: `POST divi/v1/global-data/global-fonts` → `et_update_option('heading_font'|'body_font')` + Cache leeren (`GlobalDataController.php:166-190`, Recht `edit_posts`).
|
||||||
|
|
||||||
|
## 3. Presets (Modul- und Optionsgruppen-Presets)
|
||||||
|
|
||||||
|
**Speicherort:** Product Setting **`et_divi_builder_global_presets_d5`** (`GlobalPreset::option_name()` = `builder_global_presets_d5`, `GlobalPreset.php:129`), autoload aus. Divi-4-Presets: `et_divi_builder_global_presets_ng` (wird bei Bedarf importiert, Flag `builder_is_legacy_presets_imported_to_d5`).
|
||||||
|
|
||||||
|
**Gespeichertes Format:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"module": {
|
||||||
|
"divi/button": { "default": "", "items": { "3gbmxlurey": { …Modul-Preset… } } },
|
||||||
|
"divi/divider": { "default": "g7kvfq5uh8", "items": { "g7kvfq5uh8": { … } } }
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"divi/font-body": { "default": "", "items": { "ja6o54jtlc": { …Gruppen-Preset… } } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Modul-Preset-Eintrag: `type: "module"`, `id`, `name`, `moduleName`, `version` (Builder-Version, hier `"5.2.1"`), `created`/`updated` (**Millisekunden**, Builder `Date.now()`; PHP-Hilfen `_generate_new_preset` nutzen `time()` in Sekunden, `:1695-1707`), `attrs`, optional `styleAttrs`, `renderAttrs`, `groupPresets`, `priority`, `order`.
|
||||||
|
Gruppen-Preset-Eintrag zusätzlich `groupName` (z. B. `divi/font-body`), `groupId` (Attributpfad im Quellmodul, z. B. `content.decoration.bodyFont`), `moduleName` (Quellmodul), optional `primaryAttrName` (nur über JS-Filter gesetzt, `module-utils.js`, Suche `divi.optionGroupPresetPrimaryAttrNameResolver`).
|
||||||
|
|
||||||
|
- **IDs** 10 Zeichen `[0-9a-z]`, ohne Präfix (Builder `generateDefaultPresetName`, `global-data.js`). Namen sind **nicht eindeutig** – der Builder zählt „Button 1, Button 2 …“.
|
||||||
|
- **`attrs`** = normale Modulattribute (Pfad wie im Block, z. B. `button.decoration.background.desktop.value.color`); Gruppen-Presets tragen die **vollen Pfade des Quellmoduls** und werden beim Anwenden auf andere Module umgerechnet (`GlobalPresetItemGroup::_attrs_resolver`, `GlobalPresetItemGroup.php:245ff`, `GlobalPresetItemGroupAttrNameResolver`).
|
||||||
|
- **`styleAttrs`/`renderAttrs`**: Teilmengen von `attrs` für CSS bzw. HTML/Skript. Serverseitig berechenbar mit `Conversion::get_preset_attrs($attrs, ['style'] | ['html','script'], Conversion::get_preset_attrs_mapping($moduleName))` (B5 `Packages/Conversion/Conversion.php:2242`, `:2479`; genutzt in `convert_preset`, `:2144-2145`). Das Frontend benutzt `renderAttrs`/`styleAttrs` der Gruppen-Presets direkt (`Packages/ModuleLibrary/ModuleRegistration.php:326-340`).
|
||||||
|
- **`groupPresets`** im Modul-Preset (verschachtelte Gruppen-Presets): `{ "<groupId>": { "presetId": ["<id>"], "groupName": "divi/…" } }`.
|
||||||
|
- **`default`** je Modul/Gruppe: ID des Standard-Presets oder `""`. Der Builder legt beim Öffnen des Preset-Managers leere Standard-Presets an (`ADD_DEFAULT_MODULE_PRESET`); ein Standard-Preset **ohne `attrs`** erzeugt keine Klasse (`get_module_preset_class_names`, `GlobalPreset.php:730-800`).
|
||||||
|
- **`priority`** fehlt meist und gilt dann als `10` (`:676`, `:2078`, `:2761`); das REST-Schema-Default `10` (`GlobalPresetController.php`, `preset_type_properties`) wird für verschachtelte Einträge nicht eingesetzt.
|
||||||
|
|
||||||
|
**Verweise in Blöcken** (`post_content`):
|
||||||
|
- Modul-Preset: `"modulePreset": ["3gbmxlurey"]` – **Array** (Stapel); ein String ist Altformat und wird noch akzeptiert (`normalize_preset_stack`, `:2627-2680`). `""`, `"default"`, `"_initial"` bedeuten „Standard-Preset“ (`is_preset_id_as_default`, `:2691`). Fehlt `modulePreset`, gilt das Standard-Preset des Moduls.
|
||||||
|
- Gruppen-Preset: `"groupPreset": { "module.decoration.spacing": { "presetId": ["apzj7e17ok"], "groupName": "divi/spacing" } }` (`get_selected_group_presets`, `:2021-2320`; Überlagerung `:2148`).
|
||||||
|
- Stapel: letztes Element gewinnt bei `get_selected_preset` (`:522-600`); `renderAttrs` werden nach `priority` aufsteigend gemischt (`:626-712`). Verschachtelte und explizite Gruppen-Presets werden gestapelt, nicht ersetzt (`:2148-2163`).
|
||||||
|
- Welche Gruppen ein Modul hat und wie sie heißen: `GlobalPreset::get_group_preset_default_attr(ModuleRegistration::get_module_settings($name))` (`:2332-2465`), Namensliste `get_default_group_name` (`:2475-2511`). Beispiel `divi/text`: `content.decoration.bodyFont` → `divi/font-body`, `module.decoration.spacing` → `divi/spacing`; `divi/button`: `button.decoration.font` → `divi/font`, `button.decoration.button` → `divi/button`.
|
||||||
|
|
||||||
|
**CSS-Klassen im Frontend** (`GlobalPresetItemUtils::generate_preset_class_name`, `GlobalPresetItemUtils.php:43-78`): `preset--module--divi-button--3gbmxlurey`, Standard-Preset `preset--module--divi-divider--default`, Gruppe `preset--group--divi-blurb--divi-spacing--apzj7e17ok`, verschachtelt `preset--group--divi-text--divi-font-body--nested--ja6o54jtlc`. Keine Klassen für `divi/id-classes`, `divi/animation`. Am Fixture geprüft (README in `tests/Fixtures/divi/stage4/`).
|
||||||
|
|
||||||
|
**Schreiben:** `GlobalPreset::save_data(array $data)` (`:419-431`) schreibt die **komplette Option ungeprüft**, leert Caches (`remove_static_resources('all','all',true,'all',true)` – Builder-CSS bleibt erhalten) und setzt `self::$_data` zurück. Sanitisierung gibt es nur in `GlobalPreset::prepare_data()` (`:213-268`): wandelt das REST-Format (`{module: [{default, items: [ … ]}], group: …}`, Listen statt ID-Schlüssel) ins Speicherformat, entfernt leere Attribut-Arrays und sanitisiert `attrs`/`renderAttrs`/`styleAttrs` mit `SavingUtility::sanitize_block_attrs` bzw. `sanitize_group_attrs` (`VisualBuilder/Saving/SavingUtility.php:2153`, `:2296`; ohne `unfiltered_html` wird gefiltert).
|
||||||
|
|
||||||
|
**Builder-Speicherweg:** `POST divi/v1/global-data/global-preset/sync` (`RESTRegistration.php:1035-1045`) → `GlobalPresetController::sync` (`GlobalPresetController.php:45-187`): optional in Blöcken (Transient 5 min), `prepare_data`, **`validate_preset_count`** (`GlobalPreset.php:335-410`: weniger Presets als gespeichert → Fehler 400 `preset_count_decreased`, außer `actionType` `DELETE_MODULE_PRESET`/`DELETE_OPTION_GROUP_PRESET`), bei Löschaktionen Bereinigung der Divi-4-Option (`remove_preset_from_legacy_option`), dann `save_data`. Der Builder schickt immer den **vollständigen** Bestand.
|
||||||
|
|
||||||
|
**Rechte:** `sync_permission()` = `UserRole::can_current_user_use_visual_builder()` (`GlobalPresetController.php:460`, `Framework/UserRole/UserRole.php:38-70`) – nur das Rollen-Recht „Visual Builder verwenden“ (Standard „an“), **kein** `edit_theme_options`. Dazu der Routen-Nonce wie in Abschnitt 1.
|
||||||
|
|
||||||
|
**Preset-Historie:** `et_divi_builder_presets_history_meta` (`{index, size}`) und `et_divi_builder_presets_history_item_<n>` gehören zu Divi 4 (`includes/builder/feature/global-presets/History.php:4-10`, Schreiben nur per AJAX `et_builder_save_global_presets_history` mit `switch_themes`, `:75-139`). Der Divi-5-Sync schreibt dort **nichts**; Rückgängig im Builder ist rein clientseitig. Lokal: `{index: -1, size: 0}`. Für Etappe 4 heißt das: eine Wiederherstellung gibt es nur über eigene Snapshots (Spec §7).
|
||||||
|
|
||||||
|
## 4. Theme-Optionen (`et_divi`)
|
||||||
|
|
||||||
|
Lokal ist **keiner** der Whitelist-Schlüssel gesetzt (Fixture `et-divi-subset.json`) – überall gelten Divi-Standards.
|
||||||
|
|
||||||
|
| Gruppe | Schlüssel in `et_divi` | Schreibweg in Divi | Sanitize / Standard (Customizer, `functions.php`) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Schriften | `heading_font`, `body_font`, `primary_nav_font`, `secondary_nav_font`, `all_buttons_font` | Customizer, `global-fonts`-REST (nur heading/body) | `et_sanitize_font_choices`, Standard `none` (`:2484`, `:2557`, `:3398`, `:3522`, `:4996`) |
|
||||||
|
| | `heading_font_weight`, `body_font_weight` | Customizer | `et_sanitize_global_font_weight`, `500` (`:2509`, `:2582`) |
|
||||||
|
| Größen | `body_font_size` (14), `tablet_body_font_size`, `phone_body_font_size`, `body_header_size` (30), `tablet_header_font_size`, `phone_header_font_size` | Customizer | `absint` (`:2208-2456`); Tablet/Phone-Standard = nächstgrößerer Wert |
|
||||||
|
| | `body_font_height` (1.7), `body_header_height` (1) | Customizer | `et_sanitize_float_number` (`:2236`, `:2376`) |
|
||||||
|
| | `body_header_spacing` (0), `body_header_style` (`''`) | Customizer | `et_sanitize_int_number`, `et_divi_global_font_style` (`:2348`, `:2404`) |
|
||||||
|
| Layout | `content_width` (1080), `gutter_width` (3), `section_padding` (4), `row_padding` (2) | Customizer | `absint` (`:1824`, `:1852`, `:1927`, `:2011`) |
|
||||||
|
| Farben | `accent_color`, `secondary_accent_color`, `header_color`, `font_color`, `link_color` | Customizer **und** `set_global_colors` (Abschnitt 1) | `et_sanitize_alpha_color` (`:2534-2665`) |
|
||||||
|
| Buttons | `all_buttons_*` (19 Schlüssel inkl. `*_hover`, z. B. `all_buttons_bg_color`, `all_buttons_border_radius_hover`) | Customizer | je Feld (`:4843ff`) |
|
||||||
|
| Logo | `divi_logo` | ePanel „Theme-Optionen“ | Typ `upload`, URL-String (`options_divi.php:81`) |
|
||||||
|
| SEO | `divi_seo_home_*`, `divi_seo_single_*`, `divi_seo_index_*` | ePanel | Checkboxen `'on'`/`'false'`, Texte, Selects (`options_divi.php:721-894`; Speichern `epanel/core_functions.php:868ff`, Checkbox `:969-970`/`:1049`) |
|
||||||
|
|
||||||
|
- Customizer-Einstellungen sind `type => 'option'` mit Schlüssel `et_divi[<name>]` und `capability => 'edit_theme_options'`; Divi prüft zusätzlich das Rollen-Recht `theme_customizer` (`functions.php:1278`). ePanel: `edit_theme_options` (`epanel/core_functions.php:873`) und Rollen-Recht `theme_options` (`functions.php:8834-8846`).
|
||||||
|
- **Standardwerte weichen voneinander ab:** `secondary_accent_color` hat im Customizer `#8800FF` (`functions.php:2665`), in `GlobalData::$customizer_colors` und im Builder `#2ea3f2` (`GlobalData.php:64-68`, `includes/builder/core.php:7293`). Wer die Builder-Sicht (`get_global_colors()`) zurückschreibt, setzt die Customizer-Farbe damit fest auf `#2ea3f2`. Ebenso Schriften: Customizer-Standard `none`, Builder-Sicht „Open Sans“.
|
||||||
|
- Caches: nach Customizer-Speichern `remove_static_resources('all','all')` (`core/components/PageResource.php:944`, `:1139-1141`) und `et_pb_force_regenerate_templates` (`includes/builder/core.php:3771`). Für eigene Schreibzugriffe gilt dasselbe.
|
||||||
|
|
||||||
|
## 5. Caches
|
||||||
|
|
||||||
|
`ET_Core_PageResource::remove_static_resources($post_id, $owner, $force, $slug, $preserve_vb_files, $delete_files)` (`core/components/PageResource.php:1213-1232`) läuft **nur**, wenn `wp_doing_cron()` oder `et_core_security_check_passed('edit_posts')` – ohne angemeldeten Benutzer (z. B. WP-CLI ohne `--user`) ist der Aufruf wirkungslos. Farben und Variablen rufen `('all','all',true)`, Presets `('all','all',true,'all',true)` bereits selbst auf; der in Spec §7 vorgesehene Zusatzaufruf ist harmlos, aber redundant.
|
||||||
|
|
||||||
|
In-Request-Caches: `GlobalData::$_cached_data` (Reset bei `set_*`), `GlobalPreset::$_data` und `$_normalized_preset_stack_cache` (Reset in `save_data`/`delete_data`), `static` in `get_customizer_colors()`/`get_customizer_fonts()` und `get_group_preset_default_attr()` (kein Reset).
|
||||||
|
|
||||||
|
## 6. Rechte im Überblick
|
||||||
|
|
||||||
|
| Weg | Prüfung in Divi |
|
||||||
|
|---|---|
|
||||||
|
| REST `global-colors`, `global-fonts`, `global-variables` | `edit_posts` + Routen-Nonce |
|
||||||
|
| `GlobalData::set_global_variables()` | `edit_theme_options` **und** `et_pb_is_allowed('variables_manager')`, sonst stilles `return` |
|
||||||
|
| `GlobalData::set_global_colors()`, `GlobalPreset::save_data()` | keine |
|
||||||
|
| REST `global-preset/sync` | Rollen-Recht `use_visual_builder` + Routen-Nonce |
|
||||||
|
| Customizer | `edit_theme_options` + Rollen-Recht `theme_customizer` |
|
||||||
|
| ePanel | `edit_theme_options` + Rollen-Recht `theme_options` |
|
||||||
|
| `remove_static_resources` | `edit_posts` (oder Cron), sonst wirkungslos |
|
||||||
|
|
||||||
|
## 7. Abweichungen und Ergänzungen zu Spec §7
|
||||||
|
|
||||||
|
1. **„Variablen … über `GlobalData::set_global_variables`“** – stimmt, aber die Funktion ersetzt die ganze Option, liefert keinen Fehler bei fehlenden Rechten und kennt keinen Typ `colors`. Das Tool muss vorher lesen, `stdClass` → Array wandeln, `allowedActions` und die zwei Customizer-Schriften entfernen und nach dem Schreiben per Lesen prüfen.
|
||||||
|
2. **„globale Farben … inkl. der fünf Hauptfarben (über `set_global_colors`)“** – die Hauptfarben landen in `et_divi['accent_color']` usw.; der zweite Parameter entscheidet zwischen Ersetzen (`false`) und Mischen (`true`). Für Änderungen einzelner Farben: Mischen; Löschen wie der Builder als `status: inactive`. Hauptfarben nur schicken, wenn sie wirklich geändert werden sollen (Standardwert-Abweichung, Abschnitt 4).
|
||||||
|
3. **„Presets … per Name“** – Namen sind nicht eindeutig; IDs sind 10-stellige Zeichenketten. Schreiben immer als vollständiger Bestand; `save_data()` sanitisiert nicht → vorher `prepare_data()` (REST-Format) und `validate_preset_count()` wie der Controller verwenden. `styleAttrs`/`renderAttrs` müssen mitgeschrieben werden (Frontend liest sie).
|
||||||
|
4. **„Voraussetzung: `edit_theme_options`; für Variablen zusätzlich `variables_manager`“** – strenger als Divi selbst (Farben: `edit_posts`; Presets: nur Visual-Builder-Recht). Als bewusste Plugin-Entscheidung beibehalten; für Variablen ist die Doppelprüfung zwingend, weil Divi sonst still nichts tut.
|
||||||
|
5. **„danach `remove_static_resources('all','all',true)`“** – Divis Setter tun das schon; wirkungslos ohne angemeldeten Benutzer. Für Presets nutzt Divi `preserve_vb_files = true`.
|
||||||
|
6. **Snapshots** sind die einzige Wiederherstellung: Divi 5 führt für Farben, Variablen und Presets keine serverseitige Historie; die Option `et_divi_builder_presets_history_meta` gehört zu Divi 4.
|
||||||
|
7. **Theme-Optionen:** `divi_logo` und `divi_seo_*` sind ePanel-Felder (andere Sanitize-Regeln, Checkbox-Werte `'on'`/`'false'`), keine Customizer-Einstellungen. Die übrigen Whitelist-Felder haben die Customizer-Sanitize-Callbacks aus Abschnitt 4 – diese sollten wiederverwendet werden.
|
||||||
|
8. **Lesepfad des Plugins** (`src/Integrations/Divi/Design/DesignSystem.php`): Farb-„Variablen“ (`variables['colors']`) sind in 5.2.1 immer leer – globale Farben tragen Label und ID selbst. `fonts()` liefert die Builder-Sicht („Open Sans“), nicht den Customizer-Standard `none`.
|
||||||
|
|
||||||
|
## 8. Stolpersteine (Kurzliste)
|
||||||
|
|
||||||
|
- `get_global_variables()` liefert `stdClass` je Gruppe, gespeichert sind Arrays; leere Gruppe = `{}` im JSON.
|
||||||
|
- Variableneinträge brauchen das Feld `id`; `order` wird zum String.
|
||||||
|
- `usedInPosts` muss ein Array sein; wird nur vom Builder gepflegt.
|
||||||
|
- `created`/`updated` in Millisekunden (Builder) vs. Sekunden (PHP-Hilfen).
|
||||||
|
- `modulePreset` ist ein Array; Standard-Preset wirkt nur mit `attrs`.
|
||||||
|
- Sync-Endpunkt verweigert kleinere Preset-Anzahl ohne `DELETE_*`-actionType.
|
||||||
|
- `GlobalPreset::delete_data()` löscht die Product-Setting-Option nicht.
|
||||||
|
- Divi-REST-Routen verlangen `X-ET-Nonce` pro Route; direkte PHP-Aufrufe umgehen Nonce, Schema und Rechteprüfung.
|
||||||
|
- `secondary_accent_color`: Customizer-Standard `#8800FF`, Builder-Standard `#2ea3f2`.
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 . '.');
|
||||||
Reference in New Issue
Block a user