Skip to content

Windows: Reload a saved new post, not an empty draft - #1010

Merged
epeicher merged 2 commits into
trunkfrom
opensta-265-editor-adding-photos-inside-a-post-often-fails-or-is-slow
Oct 14, 2026
Merged

epeicher merged 2 commits into
trunkfrom
opensta-265-editor-adding-photos-inside-a-post-often-fails-or-is-slow

Conversation

@epeicher

@epeicher epeicher commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

What

The title-bar Reload on a post window that was opened as a new post now reloads the saved post. Before, it opened a brand-new empty draft, so the post and the photos just added to it looked gone.

Why

On WordPress 7.1 the block editor turns on client-side media processing. In Chromium 137+ (on HTTPS or localhost) it sends Document-Isolation-Policy: isolate-and-credentialless on post.php / post-new.php. The editor frame then lives in its own agent cluster: the shell can still postMessage it, but contentWindow.location.reload() throws.

Window.reload() caught that and fell back to iframe.src = iframe.src. After a first save, Gutenberg moves its own URL from post-new.php to post.php?post=N with replaceState, and src never changes. So the fallback loaded post-new.php again.

The fallback now loads getCurrentUrl(), the URL the page last reported, which reload() already computes for its other paths.

Investigation notes

This came out of looking into reports that adding photos to a post in a window fails or is slow. Every upload path worked and was as fast as classic wp-admin, in a window and outside one:

  • Image block upload
  • Gallery
  • Dropping on the canvas, including several files and a real Finder drag
  • Paste
  • The media modal
  • An iPhone HEIC, which WordPress converts to JPEG in the browser

Every image got all its sub-sizes, and every request returned 2xx. The older "often doesn't work" report predates #962, which stopped the bridge's request tracking from holding on to upload bodies. The Reload bug was the one real defect found.

Testing

  1. Open a new post in a window (post-new.php).
  2. Add an image and save the draft.
  3. Click Reload in the window's title bar.
  4. The window reopens post.php?post=N with the image, not an empty new draft.

tests/vitest/window-unsaved-navigation.test.ts covers the fallback and fails without the fix. npm run build, npm run lint, npm run typecheck and npm run test:js pass.

Open WordPress Playground Preview

On WordPress 7.1 the block editor is sent with
Document-Isolation-Policy in Chromium, so the shell cannot call the
editor frame's location.reload(). The title-bar Reload then fell back
to re-assigning the iframe's src. A window opened on post-new.php keeps
that src after the first save, even though the editor has moved itself
to post.php?post=N, so Reload opened a brand-new empty draft and the
post with its photos looked gone.

The fallback now loads the URL the page last reported, which is what
the reload already uses everywhere else.
@epeicher

Copy link
Copy Markdown
Collaborator Author

@claude please review this

@claude

claude Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Claude finished @epeicher's task in 23s —— View job


Review of #1010: Reload a saved new post, not an empty draft

Verdict: looks good. I found no blocking issues.

  • Read the diff (src/window/index.ts, tests/vitest/window-unsaved-navigation.test.ts)
  • Checked getCurrentUrl() and withChromelessParam() to confirm the fallback is safe
  • Checked the test

What I checked

  • The fix is correct. In reload(), reloadedUrl = this.getCurrentUrl() is already computed for the primary tab. When contentWindow.location.reload() throws, getCurrentUrl() (src/window/index.ts:1220) returns _reportedLocation.url, but only if reported.src === iframe.src. That check means a stale report can't win after the frame has been pointed somewhere else.
  • The fallback behaves like the old one in the other cases. If the frame is detached, or no report exists, getCurrentUrl() returns iframe.src. withChromelessParam( src ) then returns the same URL, or the same URL with openstation_chromeless=1 set. The result is the same as iframe.src = iframe.src.
  • The cross-origin and shell-URL gate still applies. withChromelessParam returns null for another origin or for the shell document. The ?? iframe.src then falls back to the old behaviour. A reported URL that points at the shell can't boot a second desktop in the window.
  • The chromeless flag is re-applied. A reported URL such as post.php?post=52&action=edit may have lost the flag, since Gutenberg uses replaceState. The flag is added back here, and the test asserts it.
  • The test is sound. It sets src to post-new.php and the reported URL to post.php?post=52, and it checks the resulting src. It covers the real regression and goes in an existing test file, as AGENTS.md asks.

Non-blocking notes

  1. Stale URL after the unsaved-changes prompt. reloadedUrl is captured when you click, before the unsaved-changes guard resolves. If the page reports a new location while that prompt is open, the fallback loads the older one. This is a narrow window and it was already the case for the other reload paths. A fix would be to read this.getCurrentUrl() inside the catch. I wouldn't hold the PR for it.
  2. External tabs have the same pattern. The fallback at entry.iframe.src = entry.url reloads the tab's original URL, not where the page navigated to. If external tabs can also be isolated pages whose URL changes with replaceState, they could have the same bug. They may not, because they are usually cross-origin and so not reportable. It's worth knowing about, but it's out of scope here.
  3. Stray docblock. The docblock above withChromelessParam in src/window/dom.ts is separated from the function by namesAnotherWindowsTab. That predates this PR and is unrelated.

I didn't run the build, lint or test commands. The PR description says they pass, and CI will check them.

@epeicher

Copy link
Copy Markdown
Collaborator Author

Thanks for the review. I'm leaving the three non-blocking notes as they are:

  1. Reported URL changing while the unsaved-changes prompt is open: this can't happen in practice. While the browser's "Leave site?" dialog is up, the page's scripts are paused, so the editor can't save or replaceState to a new URL until the user answers. The other reload paths already capture the URL at click time the same way.
  2. External tabs: they reload entry.url because those pages are cross-origin and never report a location, so there is nothing newer to load. That's out of scope here, and we haven't seen a bug there.
  3. Docblock in src/window/dom.ts: it predates this PR and is unrelated to it, so I'm keeping it out of this diff.

@epeicher
epeicher merged commit aeb69c9 into trunk Oct 14, 2026
7 checks passed
@epeicher
epeicher deleted the opensta-265-editor-adding-photos-inside-a-post-often-fails-or-is-slow branch October 14, 2026 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant