$details Extra keys for the client, e.g. fields or usages. */ public static function make(string $code, string $message, string $hint, int $status, array $details = []): WP_Error { $payload = array_merge(['code' => $code, 'message' => $message, 'hint' => $hint], $details); $json = wp_json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); return new WP_Error( 'lit_' . $code, is_string($json) ? $json : $message, array_merge(['status' => $status, 'hint' => $hint], $details) ); } public static function forbidden( string $message, string $hint = 'Mit den Rechten des verbundenen WordPress-Kontos nicht erlaubt; ggf. Administrator fragen.' ): WP_Error { return self::make('forbidden', $message, $hint, 403); } /** * @param array $fields Input path => problem. */ public static function invalidInput( string $message, array $fields = [], string $hint = 'Die unter fields genannten Eingaben korrigieren und erneut senden.' ): WP_Error { return self::make('validation_failed', $message, $hint, 400, $fields === [] ? [] : ['fields' => $fields]); } public static function notFound( string $message, string $hint = 'ID prüfen, z. B. über lit/content-query (direkt: lit-content-query) oder lit/media-search ' . '(direkt: lit-media-search) suchen.' ): WP_Error { return self::make('not_found', $message, $hint, 404); } /** $message/$hint replace the post-oriented defaults (e.g. for the menu lock menu_rev). */ public static function revMismatch(?string $message = null, ?string $hint = null): WP_Error { return self::make( 'rev_mismatch', $message ?? 'Der Inhalt wurde seit dem letzten Lesen geändert; nichts wurde geschrieben.', $hint ?? 'Neu lesen (z. B. lit/content-get, direkt: lit-content-get) und die Änderung auf dem aktuellen ' . 'Stand wiederholen.', 409 ); } /** * @param list> $usages * @param string|null $hint Replaces the default hint (force: true, for lit/media-delete). */ public static function inUse(string $message, array $usages, ?string $hint = null): WP_Error { return self::make( 'in_use', $message, $hint ?? 'Verwendungen prüfen; nur mit force: true trotzdem ausführen.', 409, ['usages' => $usages] ); } /** * @param array $details */ public static function confirmRequired(string $message, array $details = []): WP_Error { return self::make( 'confirm_required', $message, 'Beim Nutzer nachfragen und dann mit confirm: true erneut aufrufen.', 409, $details ); } public static function unsupported(string $message, string $hint): WP_Error { return self::make('unsupported', $message, $hint, 400); } /** * Unknown Divi attribute paths (spec §5.4, §8.2). $fields names every problem of the call, * the unknown paths with their closest known ones. * * @param array $fields Input path => problem. */ public static function invalidAttrPath(array $fields): WP_Error { return self::make( 'invalid_attr_path', 'Unbekannte Attributpfade; nichts wurde gespeichert.', 'Vorschläge unter fields prüfen; alle gültigen Pfade eines Moduls liefert lit/divi-catalog ' . '(direkt: lit-divi-catalog) mit module.', 400, ['fields' => $fields] ); } /** * A write failed and was rolled back completely. * * @param array $details Extra error details (e.g. a backup that stays). * @param string|null $hint Replaces the default hint (e.g. "re-read before retrying"). * @param string|null $state Replaces "Nichts wurde gespeichert." when the rollback left * something behind on purpose (a backup or revision). */ public static function writeFailed( string $reason, array $details = [], ?string $hint = null, ?string $state = null ): WP_Error { return self::make( 'write_failed', trim('Speichern fehlgeschlagen: ' . $reason) . ' ' . ($state ?? 'Nichts wurde gespeichert.'), $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 ); } /** * The $state for writeFailed() when a clean rollback deliberately keeps something, e.g. * "Revision 811" or "Sicherung 88": the change itself is not saved, but "Nichts wurde * gespeichert" would be untrue. */ public static function notSavedKeeping(string $kept): string { return sprintf('Die Änderung wurde nicht gespeichert (%s bleibt erhalten).', $kept); } /** * A write failed and could not be rolled back completely – something may have been saved. * $state and $hint replace the post-oriented defaults for writes that are not about a post * (e.g. menus); $extra is merged into the error details. * * @param array $extra */ public static function partialWrite( string $reason, ?int $postId = null, ?int $revisionId = null, ?string $state = null, ?string $hint = null, array $extra = [] ): WP_Error { $state ??= $postId === null ? 'Möglicherweise wurde trotzdem ein Entwurf angelegt.' : sprintf('Eintrag %d ist möglicherweise teilweise geändert bzw. angelegt worden', $postId) . ($revisionId === null ? '.' : sprintf(' (Stand vorher: Revision %d).', $revisionId)); $details = array_merge($extra, array_filter( ['post_id' => $postId, 'revision_id' => $revisionId], static fn (?int $id): bool => $id !== null )); return self::make( 'partial_write', trim('Speichern fehlgeschlagen: ' . $reason) . ' Die Änderung konnte nicht vollständig zurückgenommen ' . 'werden. ' . $state, $hint ?? 'Den Aufruf nicht einfach wiederholen. Zuerst den aktuellen Stand prüfen (lit/content-get, ' . 'direkt: lit-content-get; bei einem neuen Entwurf lit/content-query, direkt: lit-content-query) ' . 'und ggf. mit lit/revisions-list und lit/revision-restore (über mcp-adapter-execute-ability) den ' . 'vorherigen Stand wiederherstellen; dem Nutzer Bescheid geben.', 500, $details ); } /** The client message of an error (its JSON "message"), without the JSON around it. */ public static function clientMessage(WP_Error $error): string { $data = json_decode($error->get_error_message(), true); return is_array($data) && is_string($data['message'] ?? null) ? $data['message'] : $error->get_error_message(); } /** The error code as the client sees it (without the "lit_" prefix of the WP_Error code). */ public static function codeOf(WP_Error $error): string { return (string) preg_replace('/^lit_/', '', (string) $error->get_error_code()); } /** * The `fields` of a validation error (input path => problem); [] when it has none. * * @return array */ public static function fieldsOf(WP_Error $error): array { $data = $error->get_error_data(); return is_array($data) && is_array($data['fields'] ?? null) ? $data['fields'] : []; } public static function internal(): WP_Error { return self::make( 'internal_error', 'Interner Fehler bei der Ausführung. Details stehen im PHP-Error-Log der Website.', 'Später erneut versuchen oder den Administrator der Website informieren.', 500 ); } }