refactor: PostRow::update and PostGuard::assertNoMissedSchedule (M5)

- PostRow::update(id, columns, failure) / ::save(): the slashed wp_update_post of
  internal row writes, refusals as RuntimeException '<failure>: <why>'. Used by
  ContentUpdate::restoreRow, PostCloner::updateRow, MediaMetaWriter apply/restore.
- PostGuard::assertNoMissedSchedule(postId, message) replaces the re-read + check in
  ContentUpdate::restoreRow, PostCloner and DiviSaver::restore (DiviSaver keeps its
  own kses window; M4).
- PostCloner::restore uses Rollback::attempt.
Log messages unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-26 17:42:33 +02:00
co-authored by Claude Opus 5.5
parent 8e5ba9eac4
commit 4114bdb805
8 changed files with 140 additions and 49 deletions
@@ -4,8 +4,10 @@ declare(strict_types=1);
namespace LIT\MCP\Integrations\WordPress\Status;
use LIT\MCP\Abilities\Rollback;
use LIT\MCP\Abilities\WriteFailed;
use LIT\MCP\Integrations\WordPress\PostGuard;
use LIT\MCP\Integrations\WordPress\PostRow;
use RuntimeException;
use Throwable;
use WP_Error;
@@ -143,14 +145,7 @@ class PostCloner
'meta' => fn () => $this->replaceMeta($postId, $snapshot['meta']),
'terms' => fn () => $this->setTerms($postId, $snapshot['terms']),
];
$failures = [];
foreach (array_intersect_key($steps, array_flip($parts)) as $step) {
try {
$step();
} catch (Throwable $e) {
$failures[] = $e->getMessage();
}
}
$failures = Rollback::attempt(...array_values(array_intersect_key($steps, array_flip($parts))));
if ($failures !== []) {
throw new RuntimeException('Restore incomplete: ' . implode('; ', $failures));
@@ -225,11 +220,7 @@ class PostCloner
private function updateRow(int $postId, array $columns): void
{
$this->assertNoMissedSchedule($postId);
$result = wp_update_post(wp_slash(array_merge(['ID' => $postId], $columns)), true);
if ($result instanceof WP_Error || ! $result) {
$message = $result instanceof WP_Error ? $result->get_error_message() : 'unknown error';
throw new RuntimeException(sprintf('Post %d could not be updated: %s', $postId, $message));
}
PostRow::update($postId, $columns, sprintf('Post %d could not be updated', $postId));
}
/**
@@ -239,13 +230,10 @@ class PostCloner
*/
private function assertNoMissedSchedule(int $postId): void
{
$post = get_post($postId);
if ($post instanceof WP_Post && PostGuard::missedSchedule($post)) {
throw new RuntimeException(sprintf(
'Post %d not written: saving it now would publish a missed schedule.',
$postId
));
}
PostGuard::assertNoMissedSchedule(
$postId,
sprintf('Post %d not written: saving it now would publish a missed schedule.', $postId)
);
}
/**