fix(submit): make the draft chain survive continuous writing, reloads and flaky networks

Autosave only ran after 4s of idle, and every keystroke reset that timer, so a
writer who never stopped had zero saves (measured: 15s of typing = 0 requests).
Saving also never rebound the URL, so a new draft could not be found again after
a reload, the local backup was cleared on every autosave, and a failed save had
no retry and stayed failed once the network came back.

Client
- autosave: keep the idle debounce but add a 30s max-wait window that is not
  reset by further keystrokes, and retry failures at 5s / 15s / 60s
- bind `?edit=<id>` into the URL once the server returns a post id, so reloads,
  new tabs and history all reopen the same draft
- only clear the local backup when the save settled and nothing changed since
- key the local backup by draft id instead of the constant `jio-studio-0`
- restore snapshots through hydrateBlocks so code blocks come back editable
- never disable publish while an autosave is in flight, and mark autosave
  states separately (自动保存中… / 已自动保存 / 自动保存失败,将重试)
- on 409, adopt the server rev and tell the author instead of failing silently
- status bar reports the real save state instead of a bogus Markdown hint

Server
- draft saves no longer rewrite the lifecycle: pending / future / publish /
  private posts keep their status, so an autosave cannot pull a submitted post
  out of the review queue
- drafts and autosaves stop consuming the publish flood quota, which is meant to
  cap actual publishing (measured: 4 drafts used to burn 4 slots)
- autosave skips wp_save_post_revision for both plain drafts and submission
  versions; manual saves and submits still create a revision to roll back to
- media-only drafts (image / table / code / hr) count as content
- the response now carries the resulting status so the client can tell
  "just submitted" from "still under review"

Tests cover the max-wait window, retry schedule, URL binding, backup clearing,
status labelling and every server-side draft rule.
This commit is contained in:
kate522 committed 2026-11-10 17:58:22 +08:00
1 parent ec582ac9f9
commit a5386f72c6
10 files changed
+330 -49

No files matched your search

@@ -9,7 +9,7 @@
import { __, sprintf } from '@wordpress/i18n';
import { SaveState, type SaveStateValue } from './save-state';
import { SaveState, saveStateLabel, type SaveStateValue } from './save-state';
type Props = {
charCount: number;
@@ -93,6 +93,8 @@ export function StatusBar({
}: Props) {
const savedAt = saveState.at ? relativeTime(saveState.at) : '';
const status = STATUS_LABELS[saveState.state] || STATUS_LABELS.ready;
// 时间和状态各显示一次会重复(「17:04:15 · 草稿」),有具体时间时以时间为准。
const meta = savedAt || status;
return (
<footer className="jio-creator__status" role="contentinfo">
@@ -100,13 +102,13 @@ export function StatusBar({
<span className="jio-creator__status-count">
{__('字数', 'jio')}:{charCount}
</span>
<span className="jio-creator__status-mode">{__('Markdown 语法输入中', 'jio')}</span>
<span className="jio-creator__status-mode">{saveStateLabel(saveState)}</span>
</div>
<div className="jio-creator__status-meta">
<SaveState value={saveState} />
<span className="jio-creator__status-dot" aria-hidden="true">·</span>
<span className="jio-creator__status-time">{savedAt || status}</span>
<span className="jio-creator__status-time">{meta}</span>
</div>
<div className="jio-creator__status-actions">