'object', 'properties' => array_merge(DiviSchema::write(), [ 'source_post_id' => ['type' => 'integer', 'minimum' => 1], 'source_id' => ['type' => 'string', 'description' => 'Pfad-ID des Knotens in der Quelle.'], 'source_tree_rev' => ['type' => 'string', 'description' => 'tree_rev der Quelle (lit-divi-outline).'], ], DiviSchema::position()), 'required' => ['post_id', 'tree_rev', 'source_post_id', 'source_id', 'source_tree_rev'], 'additionalProperties' => false, ]; } public function annotations(): array { return Annotations::write(false); } public function isDirect(): bool { return false; } /** * lit/divi-insert's Tools-tab state, then the source's own rights and, for a library entry as * source, the rights of an insert from the library – in permission() and execute(). */ protected function precheck(array $input): ?WP_Error { if ($this->diviWritable !== null && ! ($this->diviWritable)()) { return Errors::unsupported( 'Divi-Änderungen sind für diese Verbindung abgeschaltet (Gruppe „Divi“ auf „nur lesen“ oder ' . 'lit-divi-insert deaktiviert).', 'Einen Administrator fragen: Einstellungen → LIT MCP → Tools.' ); } $source = $this->loader->load($input['source_post_id'] ?? null, false); if ($source instanceof WP_Error) { return $source; } return $source->isLibraryItem() ? $this->libraryInsertRefusal() : null; } /** E3/audit L5: copying out of a library entry is inserting from the library (lit-library-insert). */ private function libraryInsertRefusal(): ?WP_Error { if ($this->libraryInsertable !== null && ! ($this->libraryInsertable)()) { return Errors::unsupported( 'Einfügen aus der Divi-Bibliothek ist für diese Verbindung abgeschaltet (lit-library-insert ' . 'deaktiviert oder Gruppe „Divi-Bibliothek“ auf „nur lesen“).', 'Einen Administrator fragen: Einstellungen → LIT MCP → Tools.' ); } return $this->loader->library()?->canInsert(); } protected function change(DiviPage $page, array $input, DiviComposition $composition): DiviChange|WP_Error { $source = $this->loader->load($input['source_post_id'] ?? null, false); if ($source instanceof WP_Error) { return $source; } if (! is_string($input['source_tree_rev'] ?? null) || $input['source_tree_rev'] !== $source->treeRev()) { return Errors::revMismatch( 'Die Quelle wurde seit dem letzten Lesen geändert (source_tree_rev passt nicht); nichts wurde ' . 'gespeichert.', 'Die Quelle mit lit-divi-outline neu lesen und source_tree_rev sowie die Pfad-ID übernehmen.' ); } $id = is_string($input['source_id'] ?? null) ? $input['source_id'] : ''; $node = $source->index->find($id); if ($node === null) { return DiviErrors::unknownNode($id, $source->post); } $copy = $node->copy(); if ($source->isLibraryItem()) { // Finding 9: library entries from Divi's dialog use CRLF; unified before every takeover // (LibraryContent::load), as lit-library-insert and lit/library-save do. $copy->unifyLineBreaks(); } $problems = $composition->storedGuard()->problems($copy); if ($problems !== []) { return Errors::invalidInput( 'Der Knoten enthält Einstellungen, die nur im Divi-Builder übertragen werden dürfen; nichts wurde ' . 'gespeichert.', ['source_id' => implode('; ', $problems)] ); } $editor = $composition->editor(); $position = $editor->position($page->index, $input); if (is_string($position)) { return DiviErrors::position($position); } $violation = $editor->insert($position, [$copy]); if ($violation !== null) { return Errors::invalidInput( 'Der Knoten passt nicht an diese Stelle; nichts wurde gespeichert.', ['source_id' => $violation] ); } return (new DiviChange(sprintf('Knoten %s aus Eintrag %d kopiert', $id, (int) $source->post->ID))) ->record($copy, 'inserted'); } }