Skip to content

fix: count Who's Online overflow from the heartbeat total - #406

Merged
josephfusco merged 2 commits into
WordPress:mainfrom
jigneshbhavani:fix/360-overflow-count-from-total
Aug 31, 2026
Merged

josephfusco merged 2 commits into
WordPress:mainfrom
jigneshbhavani:fix/360-overflow-count-from-total

Conversation

@jigneshbhavani

@jigneshbhavani jigneshbhavani commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

The load render is correct and the first tick regresses it. render() branches on the full overflow list, so 50 people online loads as +47 more — view all users. The tick response caps at VISIBLE_ROWS + OVERFLOW_THRESHOLD, the client splits 3 visible rows off that capped array, and overflow.length > overflowThreshold can never be true afterwards, so the link is replaced by a +19 more expandable list and 28 people become unreachable.

Both the branch and the count now come from presence-online-total, which was already in the response and unread.

The decision this needed that the issue does not cover. presence-online-total counted the viewer, while render() and the widget JS both filter the viewer out, so the total was one too high and could not be used as it stood. Rather than subtracting one on the client, heartbeat_received() now filters the viewer the same way render() does, through a shared without_current_user(). Two consequences worth your review:

  • presence-online no longer carries the viewer's own entry. Three existing tests asserted that it did, including one where the viewer was the only person in the room. They now assert the same payload shape against a second user.
  • It also fixes the cap boundary. The cap ran before the viewer was filtered, so at exactly 23 other users the client received 22 and the expanded list silently dropped one.

The client signature now leads with the total. Without that, a user leaving from below the cap moves the count while the capped entries stay identical, and the widget keeps showing the old number.

One correction to the issue body: the count saturates at 19, not 20, for the same off by one reason.

Verified on a local site with 50 users online. Before: server render +47 more — view all users, first tick payload entries: 23, total: 51, widget then shows +19 more with the link gone. After: same server render, payload total: 50, widget still shows +47 more — view all users.

PHPUnit goes 401 to 403, both green. The new e2e spec covers the tick, and its second phase covers the stale count. Each new guard was mutation checked.

Fixes #360

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Implementation, the PHPUnit and e2e tests, and the local reproduction rig. I reviewed the change and checked the before and after on a local site before opening this.

@github-actions

Copy link
Copy Markdown
Contributor

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.

Core Committers: Use this line as a base for the props when committing in SVN:

Props bejignesh, joefusco.

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 commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

🛝 WordPress Playgrounds

Built from 11251ad

5 users 40 users
Single site Launch single site, 5 users Launch single site, 40 users
Multisite Launch multisite, 5 users Launch multisite, 40 users

@codecov

codecov Bot commented Aug 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.81%. Comparing base (4c88a4f) to head (11251ad).

Additional details and impacted files
@@             Coverage Diff              @@
##               main     #406      +/-   ##
============================================
- Coverage     96.85%   96.81%   -0.04%     
- Complexity      239      240       +1     
============================================
  Files            19       19              
  Lines          2826     2828       +2     
============================================
+ Hits           2737     2738       +1     
- Misses           89       90       +1     
Flag Coverage Δ
multisite 96.81% <100.00%> (-0.04%) ⬇️
phpunit 71.42% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@josephfusco
josephfusco force-pushed the fix/360-overflow-count-from-total branch from 10008a7 to 46d270b Compare August 28, 2026 22:05
github-actions Bot added a commit that referenced this pull request Aug 28, 2026

@josephfusco josephfusco left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Fix itself is right, but the e2e failure is this spec's own: tick() only counts ticks that carry presence-online, so it times out whenever the page-load tick wins its leader-election race and the forced tick comes back presence-online-unchanged (moving the seeder wpCli call inside the try, after visitAdminPage, makes the next tick a state change either way), and separately test_heartbeat_payload_holds_every_other_user_at_the_expandable_maximum still passes with array_slice( $entries, ... ) reverted because add_user_to_room( 'dashboard', 0 ) ties every timestamp so the viewer sorts last, which $i + 1 fixes.

Comment thread tests/e2e/presence-widgets.test.js Outdated
Comment thread tests/widgets/test-widget-whos-online.php Outdated
The tick response caps at VISIBLE_ROWS + OVERFLOW_THRESHOLD, so the capped
array can never exceed the threshold and summary mode was unreachable after
the first tick. Branch and count on presence-online-total instead.

presence-online-total counted the viewer while every display path filters
them out, so heartbeat_received() now filters through the same helper as
render(). That also fixes the cap boundary, where at exactly 23 other users
the client received 22 and the expanded list silently dropped one.
The e2e spec seeded the room before the page load, so whenever the load
tick carried the final state the forced tick came back
presence-online-unchanged and the listener never fired. Seed after the
load instead, which makes the next tick a state change either way.

The payload guard seeded every user at the same date_gmt, which
wp_get_presence() orders by, so where the viewer landed in the tie decided
whether the guard caught anything. Stagger the ages so the viewer is newest
and sorts first by construction.
@jigneshbhavani
jigneshbhavani force-pushed the fix/360-overflow-count-from-total branch from 46d270b to 11251ad Compare August 31, 2026 07:31
github-actions Bot added a commit that referenced this pull request Aug 31, 2026

@josephfusco josephfusco left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the adjustments. Looks good!

@josephfusco
josephfusco merged commit 3b68fe0 into WordPress:main Aug 31, 2026
25 checks passed
@josephfusco josephfusco added the [Area] Widgets Issues for the dashboard widgets label Sep 4, 2026
@josephfusco josephfusco added this to the 0.3.0 milestone Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Area] Widgets Issues for the dashboard widgets

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Who's Online overflow count saturates at 20 and the summary link is unreachable

2 participants