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
+4 -3
View File
@@ -102,14 +102,15 @@ final class Errors
* A write failed and was rolled back completely.
*
* @param array<string, mixed> $details Extra error details (e.g. a backup that stays).
* @param string|null $hint Replaces the default hint (e.g. "re-read before retrying").
*/
public static function writeFailed(string $reason, array $details = []): WP_Error
public static function writeFailed(string $reason, array $details = [], ?string $hint = null): WP_Error
{
return self::make(
'write_failed',
trim('Speichern fehlgeschlagen: ' . $reason) . ' Nichts wurde gespeichert.',
'Eingaben prüfen, ggf. korrigieren und erneut versuchen; tritt der Fehler wieder auf, den Administrator '
. 'informieren (Details im PHP-Error-Log der Website).',
$hint ?? 'Eingaben prüfen, ggf. korrigieren und erneut versuchen; tritt der Fehler wieder auf, den '
. 'Administrator informieren (Details im PHP-Error-Log der Website).',
500,
$details
);
+5 -3
View File
@@ -14,7 +14,8 @@ use WP_Error;
* client-safe German text. The AbilityRegistrar logs the detail and returns toError():
* lit_write_failed when everything was rolled back, lit_partial_write otherwise.
* $state/$hint customise the partial-write error for writes that are not about a post (see
* Errors::partialWrite()); $details are added to either error.
* Errors::partialWrite()); $details are added to either error. $rolledBackHint replaces the
* default hint of the write_failed error.
*/
final class WriteFailed extends RuntimeException
{
@@ -28,7 +29,8 @@ final class WriteFailed extends RuntimeException
string $detail = '',
public readonly ?string $state = null,
public readonly ?string $hint = null,
public readonly array $details = []
public readonly array $details = [],
public readonly ?string $rolledBackHint = null
) {
$internal = $detail !== '' ? $detail : ($previous !== null ? $previous->getMessage() : $reason);
parent::__construct(
@@ -41,7 +43,7 @@ final class WriteFailed extends RuntimeException
public function toError(): WP_Error
{
return $this->rolledBack
? Errors::writeFailed($this->reason, $this->details)
? Errors::writeFailed($this->reason, $this->details, $this->rolledBackHint)
: Errors::partialWrite(
$this->reason,
$this->postId,