Files
WP-LIT-MCP/tests/Integration/divi-seed-stage4-design.php
janniclas.loosenandClaude Opus 5.5 2e4309cb42 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
2026-09-30 06:03:54 +02:00

559 lines
25 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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 . '.');