Skip to content

Real-time collaboration: Fix disconnect dialog on navigate#75886

Merged
alecgeatches merged 4 commits intoWordPress:trunkfrom
Automattic:fix/disconnect-dialog-on-navigate
Feb 26, 2026
Merged

Real-time collaboration: Fix disconnect dialog on navigate#75886
alecgeatches merged 4 commits intoWordPress:trunkfrom
Automattic:fix/disconnect-dialog-on-navigate

Conversation

@alecgeatches
Copy link
Copy Markdown
Contributor

@alecgeatches alecgeatches commented Feb 25, 2026

What?

Prevents the "You are currently disconnected from the collaborative editing server" dialog from briefly flashing when refreshing a page during real-time collaboration. This dialog can appear (inconsistently) on reload and page navigation from a post:

Screen.Recording.2026-02-24.at.5.03.26.PM.mov

Why?

When a user refreshes the page while a polling request is in-flight, the browser aborts the fetch as part of navigation. The polling manager's catch block interprets this as a server disconnection and sets the connection status to disconnected.

This causes the disconnect modal to briefly appear before the new page loads. This may be disorienting and may make it look like something has gone wrong.

The issue is intermittent in real-world circumstances, but is more likely to happen on slower connections. If the refresh happens while no poll request is in-flight, the dialog doesn't appear. In order to reliably reproduce the issue, open lib/compat/wordpress-7.0/class-wp-http-polling-sync-server.php and add this line at the end of handle_request():

+    sleep( 2 );
     return new WP_REST_Response( $response, 200 );
 }

Then when in a post, navigate or refresh the page while a wp-sync/v1/updates request is in-flight / pending. You should consistently replicate the disconnect dialog.

How?

We add a beforeunload event listener that sets an isUnloadPending flag. The beforeunload event fires before the browser aborts in-flight fetches, so by the time the poll's catch block runs, the flag is already set and we can skip emitting the disconnected status. Note that pagehide actually fires after a request fails due to navigation (i.e. the catch logic fires before we see pagehide), so it's too late to use for this purpose.

The flag is reset at the start of each poll cycle. This handles the case where the user triggers a beforeunload confirmation dialog (e.g. "You have unsaved changes?") and chooses to not leave the page. In my testing the browser pauses JavaScript execution while the native "Leave page?" dialog is displayed, so the isUnloadPending flag safely persists for the duration of the dialog. If the user clicks "Stay", JS resumes, the failed poll's catch block sees the flag and skips the disconnect emission, and the next poll cycle resets the flag so future actual disconnections are still detected.

Testing Instructions

On trunk, use the instructions above to add a sleep( 2 ) before the return in class-wp-http-polling-sync-server.php's handle_request(). Alternatively, do not add the sleep and just try a few times to see the issue naturally.

  1. Enable real-time collaboration is enabled (Admin -> Settings -> Writing, check the "Enable real-time collaboration" checkbox) and open a post for editing.
  2. Open network tools. Wait about 5 seconds for the sync polling to establish a connection and multiple /updates calls to start appearing.
  3. Refresh the page while a /update request is mid-flight, or alternatively navigate to another page.
  4. See the disconnection dialog appear during the change.

Using this PR, repeat the same instructions above. You should no longer see the disconnection dialog during purposeful page change events. Also test that if you have unsaved changes that trigger a "Leave page?" dialog, choosing "Stay" should allow polling to resume normally without suppressing future disconnect notifications.

@alecgeatches alecgeatches self-assigned this Feb 25, 2026
@alecgeatches alecgeatches marked this pull request as draft February 25, 2026 00:31
@github-actions
Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: alecgeatches <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@alecgeatches alecgeatches added [Type] Bug An existing feature does not function as intended [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration labels Feb 25, 2026
…"Show Template" view (WordPress#75590)

* Use relative position .parent traversal instead of block client ID when sharing and drawing awareness information

* Fix "Show Template" mode by mapping remote positions into absolute block paths

* Add tests for block resolution for post-editor-awareness

* Remove inner blockPathResolver, use getBlockPathForLocalClientId utility funciton

* Make utility function naming a bit easier to follow - change "getAbsolutePositionIndex()" to "convertSelectionStateToAbsolute()", have it return "localClientId" instead of "blockClientId"

* Move block lookup functions into block-lookup utils file, improve types

* Remove EditorStoreBlock from exported types

* Compare relative positions with Yjs built-in function

* Replace areSelectionsStatesEqual() relative position comparison with compareRelativePositions() as well

* Fix types and tests from crdt-user-selections

* Add a guard to avoid getting blocks when path is empty

* Rename "useConvertSelectionStateToAbsolute" to "useResolvedSelection"

* Add unit tests for getBlockPathInYdoc, resolveBlockClientIdByPath, avoid exporting inner helper functions
@alecgeatches alecgeatches merged commit 76fd4d4 into WordPress:trunk Feb 26, 2026
44 checks passed
@alecgeatches alecgeatches deleted the fix/disconnect-dialog-on-navigate branch February 26, 2026 18:21
@github-actions github-actions bot added this to the Gutenberg 22.7 milestone Feb 26, 2026
@peterwilsoncc
Copy link
Copy Markdown
Contributor

@alecgeatches Will this need to be backported to the wp/7.0 branch?

I think it ought to be as I've seen the dialog momentarily a few times.

@chriszarate chriszarate added the Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Feb 27, 2026
@github-actions github-actions bot removed the Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Feb 27, 2026
gutenbergplugin pushed a commit that referenced this pull request Feb 27, 2026
* Explicitly send a null awareness state on pagehide to remove stale cursors

* Add postSyncUpdateNonBlocking instead of sendDisconnect, construct sync payload in caller

* Avoid showing RTC disconnect dialog on expected request failure during refresh

Co-authored-by: alecgeatches <[email protected]>
@github-actions github-actions bot added the Backported to WP Core Pull request that has been successfully merged into WP Core label Feb 27, 2026
@github-actions
Copy link
Copy Markdown

I just cherry-picked this PR to the wp/7.0 branch to get it included in the next release: 162bf47

pento pushed a commit to WordPress/wordpress-develop that referenced this pull request Mar 5, 2026
CI run: #11167.

See #64595.

---

I've included a log of the Gutenberg changes with the following command:

git log --reverse --format="- %s" 022d8dd3d461f91b15c1f0410649d3ebb027207f..e499abfb843a43ac88455ca319220c5f181e1cf3 | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy

- Add documentation for contentRole and listView block supports (WordPress/gutenberg#75903)
- Interactivity Router: fix back and forward navigation after refresh (WordPress/gutenberg#75927)
- Real-time collaboration: Fix disconnect dialog on navigate (WordPress/gutenberg#75886)
- Real Time Collab: Throttle syncing for inactive tabs. (WordPress/gutenberg#75843)
- Components: Specify line-height to avoid inheriting default values (WordPress/gutenberg#75880)
- Pattern Editing: Fix sibling blocks to edited pattern not being disabled (WordPress/gutenberg#75994)
- Sync connector PHP behavior with Core backport changes (WordPress/gutenberg#75968)
- Connectors: Avoid manual string concatenation (WordPress/gutenberg#75997)
- DataForm: fix field label for panel (should not be uppercase) (WordPress/gutenberg#75944)
- Views: add support for more overrides (all developer-defined config) (WordPress/gutenberg#75971)
- Use homeUrl instead of siteUrl for link badge evaluations (WordPress/gutenberg#75978)
- DataViews: Right-align `integer` and `number` fields (WordPress/gutenberg#75917)
- Navigation Link: Compare internal links by host instead of origin (WordPress/gutenberg#76015)
- Fix: Skip scaled image sideload for images below big image threshold (WordPress/gutenberg#75990)
- Client side media cherry pick for 7.0 (WordPress/gutenberg#75998)
- Show transform dropdown previews on focus as well as hover (WordPress/gutenberg#75940) (WordPress/gutenberg#75992)
- RTC: Fix syncing of emoji / surrogate pairs (WordPress/gutenberg#76049)
- [Real-time Collaboration] Fix sync issue on refresh (WordPress/gutenberg#76017)
- Real-time collaboration: Improve disconnect dialog (WordPress/gutenberg#75970)
- DataViews: Fix filter toggle flickering when there are locked or primary filters (WordPress/gutenberg#75913) (WordPress/gutenberg#76068)
- Connectors: Dynamically register providers from WP AI Client registry (WordPress/gutenberg#76014)
- PHP-only Blocks: Reflect bound attribute values in inspector controls (WordPress/gutenberg#76040)
- Fix: Set quality and strip metadata in client-side image resize (WordPress/gutenberg#76029)
- RTC: Prevent duplicate poll cycles (WordPress/gutenberg#76059)
- RTC: Fix stale CRDT document persisted on save (WordPress/gutenberg#75975)
- RTC: Disable multiple collaborators if meta boxes are present (WordPress/gutenberg#75939)
- Directly inject styles in overlay to make styles stay consistently mounted (WordPress/gutenberg#75700)
- Real-time collaboration: Fix comment syncing on site editor (WordPress/gutenberg#75746)
- Real-time Collaboration: Bug fix for CRDT user selection and add tests (WordPress/gutenberg#75075)
- RTC: Updates from backport PR (WordPress/gutenberg#75711)
- RTC: Fix undefined array_first() call in sync storage (WordPress/gutenberg#75869)
- RTC: Fix fallthrough for sync update switch statement (WordPress/gutenberg#76060)
- Real-time collaboration: Remove block client IDs from Awareness, fix "Show Template" view (WordPress/gutenberg#75590)
- RTC: Add session activity notifications (WordPress/gutenberg#76065)
- Prevent non-reproducible Sass/CSS builds. (WordPress/gutenberg#76098)
- Block toolbar and context menu: hide pattern actions in Revisions UI (WordPress/gutenberg#76066)
- Try enabling style variation transforms for blocks in contentOnly mode (WordPress/gutenberg#75761)
- Block toolbar: hide styles dropdown in Revisions UI (WordPress/gutenberg#76119)
- Image block: fix lightbox srcset size (WordPress/gutenberg#76092)
- Fix writing flow navigation for annotation style, or any other block with border radius (WordPress/gutenberg#76072)
- Image: Hide 'Set as featured image' for in-editor revisions (WordPress/gutenberg#76123)
- Connectors: Gate unavailable install actions behind install capability (WordPress/gutenberg#75980)
- build: Exclude experimental pages from Core builds (WordPress/gutenberg#76038)
- HTML & Shortcode: Disable viewport visibility support (WordPress/gutenberg#76138)
- RTC: Verify client ID to avoid awareness mutation (WordPress/gutenberg#76056)
- wp-build: Do not remove Core's default script modules registration (WordPress/gutenberg#75705)
- wp-build: Deregister script modules before re-registering (WordPress/gutenberg#75909)
- Remove `! function_exists()` checks from PHP templates (WordPress/gutenberg#76062)
- Connectors: Update page identifier to options-connectors (WordPress/gutenberg#76156)
- Connectors: Align init hook priorities with Core overrides (WordPress/gutenberg#76161)
- Icon Block: Clean up selectors config (WordPress/gutenberg#75786)
- Icons: Fix incorrect icon slug (WordPress/gutenberg#76165)
- RTC: Enable RTC by default (WordPress/gutenberg#75739)
- Rename and visibility modals: gate shortcuts behind canEditBlock to prevent triggering in revisions UI (WordPress/gutenberg#76168)
- Fix: Block style variations not rendering in Site Editor Patterns page (WordPress/gutenberg#76122)
- Client-side media processing: only use media upload provider when not in preview mode (WordPress/gutenberg#76124)
- Notes: Disable for in-editor revisions (WordPress/gutenberg#76180)
- Core Data: Support reading revision data in useEntityProp (fixes footnotes in revisions UI) (WordPress/gutenberg#76106)
- Client-side media processing: Try plumbing invalidation to the block-editor's mediaUpload onSuccess callback (WordPress/gutenberg#76173)
- Connectors: Improve responsive layout on small screens (WordPress/gutenberg#76186)
- Interactivity API: Fix router initialization race condition on Safari/Firefox (WordPress/gutenberg#76053) (WordPress/gutenberg#76191)
- Interactivity: Fix crypto.randomUUID crash in non-secure contexts (WordPress/gutenberg#76151)


git-svn-id: https://develop.svn.wordpress.org/trunk@61843 602fd350-edb4-49c9-b593-d223f7449a82
markjaquith pushed a commit to markjaquith/WordPress that referenced this pull request Mar 5, 2026
CI run: WordPress/wordpress-develop#11167.

See #64595.

---

I've included a log of the Gutenberg changes with the following command:

git log --reverse --format="- %s" 022d8dd3d461f91b15c1f0410649d3ebb027207f..e499abfb843a43ac88455ca319220c5f181e1cf3 | sed 's|#\([0-9][0-9]*\)|https://github.com/WordPress/gutenberg/pull/\1|g; /github\.com\/WordPress\/gutenberg\/pull/!d' | pbcopy

- Add documentation for contentRole and listView block supports (WordPress/gutenberg#75903)
- Interactivity Router: fix back and forward navigation after refresh (WordPress/gutenberg#75927)
- Real-time collaboration: Fix disconnect dialog on navigate (WordPress/gutenberg#75886)
- Real Time Collab: Throttle syncing for inactive tabs. (WordPress/gutenberg#75843)
- Components: Specify line-height to avoid inheriting default values (WordPress/gutenberg#75880)
- Pattern Editing: Fix sibling blocks to edited pattern not being disabled (WordPress/gutenberg#75994)
- Sync connector PHP behavior with Core backport changes (WordPress/gutenberg#75968)
- Connectors: Avoid manual string concatenation (WordPress/gutenberg#75997)
- DataForm: fix field label for panel (should not be uppercase) (WordPress/gutenberg#75944)
- Views: add support for more overrides (all developer-defined config) (WordPress/gutenberg#75971)
- Use homeUrl instead of siteUrl for link badge evaluations (WordPress/gutenberg#75978)
- DataViews: Right-align `integer` and `number` fields (WordPress/gutenberg#75917)
- Navigation Link: Compare internal links by host instead of origin (WordPress/gutenberg#76015)
- Fix: Skip scaled image sideload for images below big image threshold (WordPress/gutenberg#75990)
- Client side media cherry pick for 7.0 (WordPress/gutenberg#75998)
- Show transform dropdown previews on focus as well as hover (WordPress/gutenberg#75940) (WordPress/gutenberg#75992)
- RTC: Fix syncing of emoji / surrogate pairs (WordPress/gutenberg#76049)
- [Real-time Collaboration] Fix sync issue on refresh (WordPress/gutenberg#76017)
- Real-time collaboration: Improve disconnect dialog (WordPress/gutenberg#75970)
- DataViews: Fix filter toggle flickering when there are locked or primary filters (WordPress/gutenberg#75913) (WordPress/gutenberg#76068)
- Connectors: Dynamically register providers from WP AI Client registry (WordPress/gutenberg#76014)
- PHP-only Blocks: Reflect bound attribute values in inspector controls (WordPress/gutenberg#76040)
- Fix: Set quality and strip metadata in client-side image resize (WordPress/gutenberg#76029)
- RTC: Prevent duplicate poll cycles (WordPress/gutenberg#76059)
- RTC: Fix stale CRDT document persisted on save (WordPress/gutenberg#75975)
- RTC: Disable multiple collaborators if meta boxes are present (WordPress/gutenberg#75939)
- Directly inject styles in overlay to make styles stay consistently mounted (WordPress/gutenberg#75700)
- Real-time collaboration: Fix comment syncing on site editor (WordPress/gutenberg#75746)
- Real-time Collaboration: Bug fix for CRDT user selection and add tests (WordPress/gutenberg#75075)
- RTC: Updates from backport PR (WordPress/gutenberg#75711)
- RTC: Fix undefined array_first() call in sync storage (WordPress/gutenberg#75869)
- RTC: Fix fallthrough for sync update switch statement (WordPress/gutenberg#76060)
- Real-time collaboration: Remove block client IDs from Awareness, fix "Show Template" view (WordPress/gutenberg#75590)
- RTC: Add session activity notifications (WordPress/gutenberg#76065)
- Prevent non-reproducible Sass/CSS builds. (WordPress/gutenberg#76098)
- Block toolbar and context menu: hide pattern actions in Revisions UI (WordPress/gutenberg#76066)
- Try enabling style variation transforms for blocks in contentOnly mode (WordPress/gutenberg#75761)
- Block toolbar: hide styles dropdown in Revisions UI (WordPress/gutenberg#76119)
- Image block: fix lightbox srcset size (WordPress/gutenberg#76092)
- Fix writing flow navigation for annotation style, or any other block with border radius (WordPress/gutenberg#76072)
- Image: Hide 'Set as featured image' for in-editor revisions (WordPress/gutenberg#76123)
- Connectors: Gate unavailable install actions behind install capability (WordPress/gutenberg#75980)
- build: Exclude experimental pages from Core builds (WordPress/gutenberg#76038)
- HTML & Shortcode: Disable viewport visibility support (WordPress/gutenberg#76138)
- RTC: Verify client ID to avoid awareness mutation (WordPress/gutenberg#76056)
- wp-build: Do not remove Core's default script modules registration (WordPress/gutenberg#75705)
- wp-build: Deregister script modules before re-registering (WordPress/gutenberg#75909)
- Remove `! function_exists()` checks from PHP templates (WordPress/gutenberg#76062)
- Connectors: Update page identifier to options-connectors (WordPress/gutenberg#76156)
- Connectors: Align init hook priorities with Core overrides (WordPress/gutenberg#76161)
- Icon Block: Clean up selectors config (WordPress/gutenberg#75786)
- Icons: Fix incorrect icon slug (WordPress/gutenberg#76165)
- RTC: Enable RTC by default (WordPress/gutenberg#75739)
- Rename and visibility modals: gate shortcuts behind canEditBlock to prevent triggering in revisions UI (WordPress/gutenberg#76168)
- Fix: Block style variations not rendering in Site Editor Patterns page (WordPress/gutenberg#76122)
- Client-side media processing: only use media upload provider when not in preview mode (WordPress/gutenberg#76124)
- Notes: Disable for in-editor revisions (WordPress/gutenberg#76180)
- Core Data: Support reading revision data in useEntityProp (fixes footnotes in revisions UI) (WordPress/gutenberg#76106)
- Client-side media processing: Try plumbing invalidation to the block-editor's mediaUpload onSuccess callback (WordPress/gutenberg#76173)
- Connectors: Improve responsive layout on small screens (WordPress/gutenberg#76186)
- Interactivity API: Fix router initialization race condition on Safari/Firefox (WordPress/gutenberg#76053) (WordPress/gutenberg#76191)
- Interactivity: Fix crypto.randomUUID crash in non-secure contexts (WordPress/gutenberg#76151)

Built from https://develop.svn.wordpress.org/trunk@61843


git-svn-id: http://core.svn.wordpress.org/trunk@61130 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backported to WP Core Pull request that has been successfully merged into WP Core [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Package] Sync [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants