Skip to content

RTC: Add session activity notifications#76065

Merged
shekharnwagh merged 14 commits intoWordPress:trunkfrom
Automattic:add/session-activity-notifications
Mar 3, 2026
Merged

RTC: Add session activity notifications#76065
shekharnwagh merged 14 commits intoWordPress:trunkfrom
Automattic:add/session-activity-notifications

Conversation

@shekharnwagh
Copy link
Copy Markdown
Contributor

@shekharnwagh shekharnwagh commented Mar 3, 2026

What?

Closes #75323

Original PR which was closed accidentally - #75790

Adds snackbar notifications for real-time collaboration session activity: when a collaborator joins, leaves, or saves the post.

Why?

Collaborator avatars in the top bar show who's present, but they're easy to miss. There's no active notification when someone joins, leaves, or saves — you'd only notice by watching the avatars constantly.

How?

  • Adds a useCollaboratorNotifications hook that compares the current and previous collaborator lists to detect joins, leaves, and remote saves.
  • Broadcasts save events to other collaborators via a new lastSaveEvent field on the awareness state.
  • Detects leaves using the isConnected property transition rather than list removal, so the notification fires when the avatar greys out (not after the 5s cleanup delay).
  • Skips notifications during initial load to avoid spurious toasts for users already present.

Testing Instructions

  1. Go to Settings > Writing > Enable real-time collaboration.
  2. Open a post for editing in two different browser tabs (or two different browsers for different users).
  3. Verify a "X has joined the post" snackbar appears in the first tab when the second tab opens the post.
  4. Close the second tab. After ~30 seconds, verify a "X has left the post" snackbar appears in the first tab.
  5. With both tabs open, save the post from the second tab. Verify a "Draft saved by X" snackbar appears in the first tab.
  6. Publish the post from the second tab. Verify a "Post updated by X" snackbar appears in the first tab.
  7. Verify no notification appears for your own saves.
  8. Verify no duplicate notifications appear on page load for users already present.

Testing Instructions for Keyboard

No new interactive UI elements are added. Snackbar notifications are announced to screen readers automatically via the existing notice system.

Screenshots or screencast

Screenshot 2026-02-24 at 7 11 17 PM
Notification when a collaborator has left

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 3, 2026

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: shekharnwagh <shekharnwagh@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
Co-authored-by: smithjw1 <smithjw1@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>

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

@github-actions github-actions bot added [Package] Core data /packages/core-data [Package] Editor /packages/editor labels Mar 3, 2026
@shekharnwagh shekharnwagh self-assigned this Mar 3, 2026
@shekharnwagh shekharnwagh added Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration labels Mar 3, 2026
@shekharnwagh shekharnwagh force-pushed the add/session-activity-notifications branch from 697ac5f to 3d910a7 Compare March 3, 2026 05:02
@shekharnwagh shekharnwagh force-pushed the add/session-activity-notifications branch from 3d910a7 to dd29227 Compare March 3, 2026 07:44
@shekharnwagh shekharnwagh force-pushed the add/session-activity-notifications branch from dd29227 to c3be201 Compare March 3, 2026 12:15
Comment on lines +774 to +782
// When sync (collaboration) is enabled, Y.Doc updates
// are deferred via setTimeout(0). Yield to the event
// loop so pending updates are flushed before
// __unstablePrePersist serializes the CRDT document.
if ( entityConfig.syncConfig ) {
await new Promise( ( resolve ) =>
setTimeout( resolve, 0 )
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When sync is enabled, Y.Doc updates are deferred via setTimeout(0).
saveEntityRecord was calling __unstablePrePersist without yielding
first, so the serialized _crdt_document was stale. On reload this
caused unnecessary reconciliation saves.

Yield to the event loop before __unstablePrePersist when syncConfig
is present so pending Y.Doc updates are flushed before serialization.
Collaborators had no way to know when others joined, left, or saved
the post. This adds snackbar notices for all four events, broadcast
via a new `lastSaveEvent` field on the Yjs awareness state.

Notification types can be toggled via the
`editor.collaborationNotifications` WordPress filter.
Replace custom awareness-based save broadcasting with the
existing CRDT state map already written by markEntityAsSaved
in @wordpress/sync.
The notification always showed "Draft saved by X" because post status
was read from the local Redux store, which lags behind the Y.Doc.

Fix by reading status from the Y.Doc record map (updated in the same
transaction as the save marker) and distinguishing three cases:
"Post published", "Post updated", and "Draft saved".
The 30 s awareness timeout matched the background-tab polling interval
exactly, causing awareness entries to expire between polls and triggering
false "X has left" notifications that resolved on the next poll cycle.

Increase to 70 s to comfortably exceed the polling interval. The value
accounts for Chrome's intensive throttling which can delay background
tab timers to ~60 s
@shekharnwagh shekharnwagh force-pushed the add/session-activity-notifications branch from c3be201 to c8c9cd5 Compare March 3, 2026 16:11
Reverts AWARENESS_TIMEOUT to 30 s and reduces the background tab
polling interval to 25 s so polls arrive before the server-side
timeout expires.
Comment on lines +123 to +139
const prevMap = new Map< number, PostEditorAwarenessState >(
prevCollaborators.map( ( c ) => [ c.clientId, c ] )
);
const newMap = new Map< number, PostEditorAwarenessState >(
activeCollaborators.map( ( c ) => [ c.clientId, c ] )
);

/*
* Detect joins: new clientIds that weren't in the previous state.
*/
if ( NOTIFICATIONS_CONFIG.userEntered ) {
const me = activeCollaborators.find( ( c ) => c.isMe );

for ( const [ clientId, collaborator ] of newMap ) {
if ( prevMap.has( clientId ) || collaborator.isMe ) {
continue;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is leaking a lot of implementation details from core-data where the state is defined. It would be better to move much of these effects and their logic back to the core-data hooks we are consuming. Something like:

useOnPostSave( postId, postType, ( saveEvent: PostSaveEvent ) => {
    /* create notice */
} );

Can be a follow-up PR.

The AWARENESS_TIMEOUT change has been reverted so a backport PR is no
longer needed.
@shekharnwagh shekharnwagh merged commit 254a9dd into WordPress:trunk Mar 3, 2026
39 checks passed
@shekharnwagh shekharnwagh deleted the add/session-activity-notifications branch March 3, 2026 17:26
@github-actions github-actions bot added this to the Gutenberg 22.7 milestone Mar 3, 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 Mar 3, 2026
gutenbergplugin pushed a commit that referenced this pull request Mar 3, 2026
* RTC: Add session activity notifications

Collaborators had no way to know when others joined, left, or saved
the post. This adds snackbar notices for all four events, broadcast
via a new `lastSaveEvent` field on the Yjs awareness state.

Notification types can be toggled via the
`editor.collaborationNotifications` WordPress filter.

* RTC: Fix collaboration presence E2E test

* RTC: Use CRDT state map for save notifications

Replace custom awareness-based save broadcasting with the
existing CRDT state map already written by markEntityAsSaved
in @wordpress/sync.

* RTC: Show correct notification when collaborator publishes

The notification always showed "Draft saved by X" because post status
was read from the local Redux store, which lags behind the Y.Doc.

Fix by reading status from the Y.Doc record map (updated in the same
transaction as the save marker) and distinguishing three cases:
"Post published", "Post updated", and "Draft saved".

* RTC: Call setUp in useLastPostSave to ensure awareness is initialized

* RTC: Remove setTimeout yield from saveEntityRecord

* RTC: Reduce background tab poll interval to avoid false disconnects

Reduces the background tab polling interval to 25 s so polls
arrive before the server-side timeout expires.

Co-authored-by: shekharnwagh <shekharnwagh@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
Co-authored-by: ingeniumed <ingeniumed@git.wordpress.org>
Co-authored-by: smithjw1 <smithjw1@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
@github-actions github-actions bot added the Backported to WP Core Pull request that has been successfully merged into WP Core label Mar 3, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 3, 2026

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

alecgeatches pushed a commit to Automattic/gutenberg that referenced this pull request Mar 3, 2026
* RTC: Add session activity notifications

Collaborators had no way to know when others joined, left, or saved
the post. This adds snackbar notices for all four events, broadcast
via a new `lastSaveEvent` field on the Yjs awareness state.

Notification types can be toggled via the
`editor.collaborationNotifications` WordPress filter.

* RTC: Fix collaboration presence E2E test

* RTC: Use CRDT state map for save notifications

Replace custom awareness-based save broadcasting with the
existing CRDT state map already written by markEntityAsSaved
in @wordpress/sync.

* RTC: Show correct notification when collaborator publishes

The notification always showed "Draft saved by X" because post status
was read from the local Redux store, which lags behind the Y.Doc.

Fix by reading status from the Y.Doc record map (updated in the same
transaction as the save marker) and distinguishing three cases:
"Post published", "Post updated", and "Draft saved".

* RTC: Call setUp in useLastPostSave to ensure awareness is initialized

* RTC: Remove setTimeout yield from saveEntityRecord

* RTC: Reduce background tab poll interval to avoid false disconnects

Reduces the background tab polling interval to 25 s so polls
arrive before the server-side timeout expires.

Co-authored-by: shekharnwagh <shekharnwagh@git.wordpress.org>
Co-authored-by: chriszarate <czarate@git.wordpress.org>
Co-authored-by: ingeniumed <ingeniumed@git.wordpress.org>
Co-authored-by: smithjw1 <smithjw1@git.wordpress.org>
Co-authored-by: maxschmeling <maxschmeling@git.wordpress.org>
@scruffian scruffian added the [Type] Enhancement A suggestion for improvement. label Mar 4, 2026
pull bot pushed a commit to tigefa4u/wordpress-develop that referenced this pull request Mar 5, 2026
CI run: WordPress#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] Core data /packages/core-data [Package] Editor /packages/editor [Package] Sync [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RTC: [Interface] Notifications for session activity

3 participants