Files
WP-LIT-MCP/src/Integrations/Divi/Pages/DiviNodeGetAbility.php
T
janniclas.loosenandClaude Opus 5.5 c7ce924e5a fix: library IDs stay hidden without library access (ruling P13)
Outline, node-get, write outlines, the render summary and replace-text's
opaque-node match name no library ID unless the library group is visible
and the user has divi_library; read-only still names them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 15:00:39 +02:00

174 lines
6.4 KiB
PHP
Raw 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
declare(strict_types=1);
namespace LIT\MCP\Integrations\Divi\Pages;
use LIT\MCP\Abilities\Ability;
use LIT\MCP\Abilities\Annotations;
use LIT\MCP\Abilities\Errors;
use LIT\MCP\Abilities\JsonMap;
use LIT\MCP\Abilities\Rev;
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
use LIT\MCP\Integrations\Divi\Schema\ShortformMap;
use WP_Error;
defined('ABSPATH') || exit;
/**
* lit/divi-node-get: all attributes of one node in the full form (spec §5.4, §5.7) –
* attribute path => breakpoint map – plus the current short-form values.
*/
final class DiviNodeGetAbility implements Ability
{
public function __construct(private DiviPageLoader $loader, private DesignSystemReader $design)
{
}
public function name(): string
{
return 'lit/divi-node-get';
}
public function label(): string
{
return 'Divi-Knoten lesen';
}
public function description(): string
{
return 'Liest einen Knoten der Divi-Seite vollständig: attrs als Attributpfad → Werte je Breakpoint '
. '(Vollform, z. B. "title.decoration.font.font": {"desktop": {"value": {…}}}), die Kurzform-Werte, '
. 'Presets und die IDs der Kinder. Pfad-IDs aus lit-divi-outline. Werte wie $variable(…)$ (globale '
. 'Farben, Variablen, dynamische Inhalte) werden unverändert angezeigt, beim Schreiben aber erneut '
. 'geprüft, nie ungeprüft übernommen.';
}
public function inputSchema(): array
{
return [
'type' => 'object',
'properties' => [
'post_id' => ['type' => 'integer', 'minimum' => 1],
'id' => ['type' => 'string', 'description' => 'Pfad-ID aus lit-divi-outline, z. B. "s0.r0.c1.m2".'],
],
'required' => ['post_id', 'id'],
'additionalProperties' => false,
];
}
public function outputSchema(): ?array
{
return [
'type' => 'object',
'properties' => [
'post_id' => ['type' => 'integer'],
'tree_rev' => ['type' => 'string'],
'rev' => ['type' => 'string'],
'id' => ['type' => 'string'],
'parent' => ['type' => ['string', 'null']],
'type' => ['type' => 'string'],
'label' => ['type' => 'string'],
'editable' => ['type' => 'boolean'],
'attrs' => ['type' => 'object'],
'shortform' => ['type' => 'object'],
'presets' => [
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => ['id' => ['type' => 'string'], 'name' => ['type' => 'string']],
'required' => ['id', 'name'],
],
],
'builder_version' => ['type' => ['string', 'null']],
'children' => ['type' => 'array', 'items' => ['type' => 'string']],
'global' => ['type' => ['object', 'null']],
],
'required' => ['post_id', 'tree_rev', 'rev', 'id', 'type', 'editable', 'attrs', 'shortform', 'children'],
];
}
public function annotations(): array
{
return Annotations::read();
}
public function isDirect(): bool
{
return true;
}
public function permission(array $input): bool|WP_Error
{
$page = $this->loader->load($input['post_id'] ?? null, false);
return $page instanceof WP_Error ? $page : true;
}
public function execute(array $input): mixed
{
$page = $this->loader->load($input['post_id'] ?? null, false);
if ($page instanceof WP_Error) {
return $page;
}
$id = is_string($input['id'] ?? null) ? $input['id'] : '';
if (preg_match(NodeIndex::ID_PATTERN, $id) !== 1) {
return Errors::invalidInput('id ist keine Pfad-ID.', ['id' => 'z. B. "s0.r1.c0.m2"']);
}
$block = $page->index->find($id);
if ($block === null) {
return DiviErrors::unknownNode($id, $page->post);
}
$names = $this->design->read()->presetNames();
$editable = $block->isDivi() && ! $block->isOpaque();
$version = $block->attrs()['builderVersion'] ?? null;
$global = NodeSummary::globalRef($block);
if ($global !== null && $this->loader->libraryIdsVisible()) {
$global['hint'] = sprintf(
'Globales Modul: Inhalt im Bibliothekseintrag %s bearbeiten (lit-divi-outline mit post_id %s); '
. 'jede Änderung dort wirkt auf alle Seiten mit diesem Modul.',
$global['id'],
$global['id']
);
} elseif ($global !== null) {
// Ruling P13: which entry is shown stays unknown without library access (AttrMap::flatten
// already leaves globalModule/globalParent out of attrs).
$global = [
'id' => null,
'block_name' => $global['block_name'],
'hint' => 'Globales Modul aus der Divi-Bibliothek – nur lesbar; dieses Konto hat keinen Zugang zur '
. 'Divi-Bibliothek.',
];
}
return [
'post_id' => (int) $page->post->ID,
'tree_rev' => $page->treeRev(),
'rev' => Rev::ofPost($page->post),
'id' => $id,
'parent' => $page->index->parentId($block),
'type' => $block->isDivi() ? $block->shortName() : $block->name(),
'label' => NodeSummary::label($block),
'editable' => $editable,
'attrs' => JsonMap::of(AttrMap::flatten($block->attrs())),
'shortform' => JsonMap::of(ShortformMap::values($block->shortName(), $block->attrs())),
'presets' => array_map(
static fn (string $presetId): array => ['id' => $presetId, 'name' => $names[$presetId] ?? ''],
NodeSummary::presetIds($block)
),
'builder_version' => is_string($version) ? $version : null,
'children' => $editable
? array_values(array_filter(array_map([$page->index, 'idOf'], $block->children())))
: [],
'global' => $global,
];
}
}