fix: media usage check fails closed on database errors; refused deletes checked for partial state

MediaUsageFinder treats a failed query (null result or last_error) as a possible
usage and an incomplete scan, so media-delete refuses without force. A refused
wp_delete_attachment() is write_failed only when the attachment is intact,
otherwise partial_write. media-update: re-read hint on write_failed, normalized
ids in failures, documented lock resolution and kses on restore.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-26 02:54:37 +02:00
co-authored by Claude Opus 5.5
parent 931ddeb137
commit 7f136f6f4c
10 changed files with 238 additions and 20 deletions
+15 -5
View File
@@ -10,6 +10,7 @@ use LIT\MCP\Abilities\FollowUp;
use LIT\MCP\Abilities\ToolResult;
use LIT\MCP\Abilities\WriteFailed;
use LIT\MCP\ChangeLog\ChangeLog;
use LIT\MCP\Integrations\WordPress\PostGuard;
use Throwable;
use WP_Error;
use WP_Post;
@@ -21,7 +22,8 @@ use WP_Post;
* changed are restored (write_failed) – or, if that fails too, partial_write names them.
*
* The `modified` lock compares post_modified_gmt, which WordPress bumps on every write of the
* posts row (title, caption, description) but not on a pure alt-text (post meta) change.
* posts row (title, caption, description) but not on a pure alt-text (post meta) change. Its
* resolution is one second: a parallel write within the same second as the read goes unnoticed.
*/
final class MediaUpdateAbility implements Ability
{
@@ -274,7 +276,17 @@ final class MediaUpdateAbility implements Ability
$detail = 'Media update failed: ' . $cause->getMessage();
if ($unrestored === []) {
throw new WriteFailed(self::REASON, true, null, null, $cause, $detail);
throw new WriteFailed(
self::REASON,
true,
null,
null,
$cause,
$detail,
rolledBackHint: 'Das Zurücksetzen hat modified der Medien geändert: vor einem neuen Versuch die Medien '
. 'neu lesen (lit/media-get oder lit-media-search) und den Stapel mit dem aktuellen modified '
. 'senden; tritt der Fehler wieder auf, den Administrator informieren (Details im PHP-Error-Log).'
);
}
$ids = [];
@@ -362,11 +374,9 @@ final class MediaUpdateAbility implements Ability
private static function failure(int $index, array $item, WP_Error $error): array
{
$payload = json_decode($error->get_error_message(), true);
$id = $item['id'] ?? null;
return [
'index' => $index,
'id' => is_int($id) ? $id : null,
'id' => PostGuard::id($item['id'] ?? null),
'code' => (string) preg_replace('/^lit_/', '', (string) $error->get_error_code()),
'error' => is_array($payload) ? (string) ($payload['message'] ?? '') : $error->get_error_message(),
];