'object', 'properties' => [ 'post_id' => ['type' => 'integer', 'minimum' => 1], 'id' => ['type' => 'string', 'description' => 'Nur diesen Teilbaum, z. B. "s1".'], 'depth' => [ 'type' => 'integer', 'minimum' => 0, 'maximum' => 10, 'description' => 'Maximale Tiefe unterhalb des Startknotens (0 = nur der Knoten).', ], 'limit' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 500, 'description' => 'Höchstzahl Kind-Knoten je Elternknoten (Standard: ' . Outline::DEFAULT_LIMIT . '). Überzählige Kinder werden abgeschnitten (truncated).', ], ], 'required' => ['post_id'], 'additionalProperties' => false, ]; } public function outputSchema(): ?array { return [ 'type' => 'object', 'properties' => [ 'post_id' => ['type' => 'integer'], 'title' => ['type' => 'string'], 'status' => ['type' => 'string'], 'tree_rev' => ['type' => 'string'], 'rev' => ['type' => 'string'], 'outline' => ['type' => 'string'], 'nodes' => [ 'type' => 'array', 'items' => [ 'type' => 'object', 'properties' => [ 'id' => ['type' => 'string'], 'type' => ['type' => 'string'], 'label' => ['type' => 'string'], 'excerpt' => ['type' => 'string'], 'info' => ['type' => 'string'], 'presets' => ['type' => 'array', 'items' => ['type' => 'string']], 'children' => ['type' => 'integer'], 'editable' => ['type' => 'boolean'], 'depth' => ['type' => 'integer'], 'truncated' => [ 'type' => 'boolean', 'description' => 'Weitere Kinder dieses Knotens wurden wegen "limit" abgeschnitten.', ], 'global_id' => [ 'type' => ['string', 'null'], 'description' => 'Bibliotheks-ID eines globalen Moduls.', ], ], 'required' => [ 'id', 'type', 'label', 'excerpt', 'info', 'presets', 'children', 'editable', 'depth', 'truncated', 'global_id', ], ], ], 'truncated' => [ 'type' => 'boolean', 'description' => 'Irgendwo im Baum wurden Kind-Knoten wegen "limit" abgeschnitten (auch auf ' . 'oberster Ebene, die kein eigenes "truncated" an einem Knoten zeigen kann).', ], 'edit_url' => ['type' => 'string'], 'hints' => ['type' => 'array', 'items' => ['type' => 'string']], ], 'required' => ['post_id', 'tree_rev', 'rev', 'outline', 'nodes', 'truncated', 'hints'], ]; } 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; } $rootId = isset($input['id']) && is_string($input['id']) && $input['id'] !== '' ? $input['id'] : null; if ($rootId !== null && preg_match(NodeIndex::ID_PATTERN, $rootId) !== 1) { return Errors::invalidInput('id ist keine Pfad-ID.', ['id' => 'z. B. "s0.r1.c0.m2"']); } if ($rootId !== null && $page->index->find($rootId) === null) { return DiviErrors::unknownNode($rootId, $page->post); } $outline = new Outline($this->design->read()->presetNames()); $rows = $outline->rows( $page->index, $rootId, isset($input['depth']) ? (int) $input['depth'] : null, isset($input['limit']) ? (int) $input['limit'] : null ); return [ 'post_id' => (int) $page->post->ID, 'title' => (string) $page->post->post_title, 'status' => (string) $page->post->post_status, 'tree_rev' => $page->treeRev(), 'rev' => Rev::ofPost($page->post), 'outline' => $outline->text($rows), 'nodes' => $rows, 'truncated' => $outline->wasTruncated(), 'edit_url' => $page->editUrl(), 'hints' => $this->hints($page, $rows), ]; } /** * @param list> $rows * @return list */ private function hints(DiviPage $page, array $rows): array { $hints = []; if ($rows === []) { $hints[] = $page->isDiviLayout() ? 'Die Seite hat noch keinen Divi-Inhalt: mit lit-divi-insert (ohne parent) den ersten Abschnitt ' . 'einfügen.' : 'Der Inhalt ist kein Divi-Layout (Block-Editor oder klassisch); lit-content-get zeigt ihn.'; } if (in_array(false, array_column($rows, 'editable'), true)) { $hints[] = 'Knoten mit "nur lesbar" (globale Module, fremde Blöcke) lassen sich nur als Ganzes ' . 'verschieben, duplizieren oder löschen. Globale Module [global ] im Bibliothekseintrag ' . 'bearbeiten: lit-divi-outline mit post_id – die Änderung wirkt auf alle Seiten.'; } return $hints; } }