'object', 'properties' => array_merge([ 'post_type' => ['type' => 'string'], 'title' => ['type' => 'string', 'minLength' => 1], 'divi' => [ 'type' => 'array', 'minItems' => 1, 'maxItems' => 30, 'items' => ['type' => 'object'], 'description' => 'Divi-Layout in Kurzform: Abschnitte wie bei lit-divi-insert (nicht zusammen mit ' . 'content). Nur wenn Divi 5 aktiv und der Divi-Builder für den Inhaltstyp eingeschaltet ist.', ], ], PostWriter::inputProperties()), 'required' => ['post_type', 'title'], 'additionalProperties' => false, ]; } public function outputSchema(): ?array { return ToolResult::schema(['tree_rev' => ['type' => 'string']]); } public function annotations(): array { return Annotations::write(false); } public function isDirect(): bool { return true; } public function permission(array $input): bool|WP_Error { $type = PostGuard::postType($input['post_type'] ?? null, $this->schema, 'create_posts'); return $type instanceof WP_Error ? $type : true; } public function execute(array $input): mixed { $type = PostGuard::postType($input['post_type'] ?? null, $this->schema, 'create_posts'); if ($type instanceof WP_Error) { return $type; } $postType = (string) $input['post_type']; $withDivi = array_key_exists('divi', $input); if ($withDivi && ($this->divi === null || ! $this->divi->available())) { return Errors::unsupported( 'Divi-Inhalt ist auf dieser Website nicht möglich (Divi 5 ist nicht aktiv); nichts wurde angelegt.', 'Ohne divi anlegen und den Inhalt über content oder im Editor setzen.' ); } $prepared = $this->writer->prepare($postType, $input, true); $problem = self::combined($prepared, $withDivi ? $this->checkDivi($postType, $input) : null); if ($problem !== null) { return $problem; } $data = array_merge($this->writer->postData($input), [ 'post_type' => $postType, 'post_status' => 'draft', 'post_author' => get_current_user_id(), ]); $draft = new NewDraft($this->writer, $this->log, $this->name(), $postType); $postId = $draft->insert($data); if ($postId instanceof WP_Error) { return $postId; } $denied = $this->writer->deniedMeta($postId, $postType, $prepared['fields'], 'add_post_meta'); if ($denied !== []) { return $draft->refuse($postId, $denied); } $layout = null; try { $layout = $withDivi ? $this->divi?->write($postId, $postType, self::sections($input)) : null; } catch (Throwable $e) { $draft->discard($postId, $e, NewDraft::REASON_EXTRAS); } if ($layout instanceof WP_Error) { return $draft->refuse($postId, $layout); } try { $this->writer->writeExtras($postId, $postType, $prepared, $input); } catch (Throwable $e) { $draft->discard($postId, $e, NewDraft::REASON_EXTRAS); } $warnings = array_merge($prepared['warnings'], $layout['warnings'] ?? []); return $this->result($postId, $postType, $input, $warnings, $layout['outline'] ?? null); } /** * The Divi description, checked completely before anything is created (spec §6.2). * * @param array $input */ private function checkDivi(string $postType, array $input): ?WP_Error { if (array_key_exists('content', $input)) { return Errors::invalidInput('content und divi schließen sich aus; nichts wurde angelegt.', [ 'content' => 'bei Divi-Inhalt weglassen', ]); } return $this->divi?->check($postType, self::sections($input)); } /** * @param array $input * @return list */ private static function sections(array $input): array { return is_array($input['divi'] ?? null) ? array_values($input['divi']) : []; } /** * One error with the fields of both checks (all or nothing: every problem comes back at once); * invalid_attr_path wins, so its suggestions stay visible. Null when both passed. * * @param array|WP_Error $prepared */ private static function combined(array|WP_Error $prepared, ?WP_Error $divi): ?WP_Error { if (! $prepared instanceof WP_Error || $divi === null) { return $prepared instanceof WP_Error ? $prepared : $divi; } $fields = array_merge(Errors::fieldsOf($prepared), Errors::fieldsOf($divi)); if ($fields === []) { return $prepared; } return $divi->get_error_code() === 'lit_invalid_attr_path' ? Errors::invalidAttrPath($fields) : Errors::invalidInput('Eingaben sind ungültig; nichts wurde angelegt.', $fields); } /** * @param array $input * @param list $warnings * @param string|null $outline Divi outline of the new layout (with divi only). * @return array */ private function result(int $postId, string $postType, array $input, array $warnings, ?string $outline): array { // The draft is saved – failures from here on are logged and reported as warnings only. $change = (new PostSaveFollowUp($this->name(), $this->log, $postId, 'der Entwurf', $warnings)) ->afterSave($input); $post = $change->reread(); $title = $post instanceof WP_Post ? (string) $post->post_title : (string) $input['title']; $change->log($postType, sprintf('Entwurf "%s" angelegt', $title)); $result = $change->result(sprintf('"%s" als Entwurf angelegt (ID %d).', $title, $postId), $post) ->changed((string) $postId, $postType, 'created', $title) ->urls((string) get_preview_post_link($postId), (string) get_edit_post_link($postId, 'raw')); if (array_key_exists('divi', $input)) { // The Divi tools lock on tree_rev (ruling P16): the next lit-divi-* call can use it right away. $result->outline($outline) ->with('tree_rev', Rev::of($post instanceof WP_Post ? (string) $post->post_content : '')); } return $result->toArray(); } }