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
559 lines
25 KiB
PHP
559 lines
25 KiB
PHP
<?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 . '.');
|