Skip to content

Stats v2: rename Premium Analytics menu and stop replacing legacy Stats - #50915

Merged
kangzj merged 5 commits into
trunkfrom
rename/premium-analytics-stats-v2
Jul 31, 2026
Merged

kangzj merged 5 commits into
trunkfrom
rename/premium-analytics-stats-v2

Conversation

@kangzj

@kangzj kangzj commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Why this matters

The bundled analytics dashboard currently shows as "Premium Analytics" (WPCOM Simple) or the generic "Analytics" (Atomic and other flag-enabled sites), and it swaps out the existing Stats menu entirely the moment it's enabled — no way back to the surface people are used to mid-rollout. This renames the dashboard to "Stats v2" and adds it as a second menu alongside the existing Stats menu, on every site, instead of replacing it.

Fixes #

Proposed changes

  • Rename the bundled dashboard's admin menu label from "Premium Analytics" (WPCOM Simple bootstrap, Premium Analytics: Wire Simple bootstrap behind gate #50266) / "Analytics" (default label, used by Atomic via Premium Analytics: enable on Atomic sites with the blog sticker #50834 and any other flag-enabled site) to "Stats v2". It already registers as its own separate top-level menu item — that didn't need to change.
  • Stop suppressing the legacy Stats menu, admin-bar entries, post-list column, and dashboard widget when Stats v2 is enabled — the two now coexist everywhere, regardless of host.
  • Update the affected unit tests and the stale doc comments describing the old unconditional "replace" behavior.

Related product discussion/links

Does this pull request change what data or activity we track or use?

Testing instructions

  • On a site with the jetpack_premium_analytics_enabled flag on (or the WPCOM Simple / Atomic rollout gates), confirm both "Stats" and "Stats v2" appear as separate top-level admin menu items, and that the Stats admin-bar entry, post-list column, and WP dashboard widget are still present.
  • jp docker phpunit jetpack --php 8.3 -- --filter "Jetpack_Premium_Analytics_Test|Stats_Admin_Bar_Test" — 15/15 pass.
  • jp test php packages/jetpack-mu-wpcom and the Analytics_Test label assertions in packages/premium-analytics — pass.

Renames the bundled dashboard's admin menu label from "Premium Analytics"
(WPCOM Simple) / "Analytics" (default, used by Atomic and other flag-enabled
sites) to "Stats v2", and removes the code that suppressed the legacy Stats
menu, admin-bar entries, post-list column, and dashboard widget whenever the
flag was on. Stats v2 now adds its own menu alongside the existing Stats UI
instead of replacing it, matching how WPCOM Simple already behaved.
@kangzj
kangzj requested a review from a team July 30, 2026 02:48
@kangzj
kangzj requested a review from a team as a code owner July 30, 2026 02:48
@kangzj kangzj added the [Status] Needs Review This PR is ready for review. label Jul 30, 2026
@kangzj kangzj self-assigned this Jul 30, 2026
@github-actions github-actions Bot added [Package] Jetpack mu wpcom WordPress.com Features [Package] Premium Analytics [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Tests] Includes Tests labels Jul 30, 2026
@github-actions

github-actions Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

No scheduled milestone found for this plugin.

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

@github-actions

github-actions Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack or WordPress.com Site Helper), and enable the rename/premium-analytics-stats-v2 branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack rename/premium-analytics-stats-v2
bin/jetpack-downloader test jetpack-mu-wpcom-plugin rename/premium-analytics-stats-v2

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@jp-launch-control

jp-launch-control Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 2 files.

File Coverage Δ% Δ Uncovered
projects/plugins/jetpack/modules/stats.php 22/551 (3.99%) -0.35% 0 💚
projects/plugins/jetpack/class-jetpack-stats-dashboard-widget.php 0/125 (0.00%) 0.00% -2 💚

Full summary · PHP report · JS report

@kangzj
kangzj marked this pull request as draft July 30, 2026 03:02
kangzj added 2 commits July 30, 2026 15:33
Narrows scope back to the label rename. The legacy Stats menu, admin-bar
entries, post-list column, and dashboard widget keep being suppressed by
the existing jetpack_premium_analytics_enabled gate exactly as before —
that gate and the "replace" behavior it drives are untouched. Stats v2
already registers its own separate top-level menu unconditionally when
enabled; nothing about that needed to change.
Scopes the existing jetpack_premium_analytics_enabled replace behavior to
exclude Atomic sites (Automattic\Jetpack\Status\Host::is_woa_site()). On
Atomic the legacy Stats menu, admin-bar entries, post-list column, and
dashboard widget now stay in place alongside the new Stats v2 menu instead
of being suppressed. Self-hosted and other WPCOM flag-enabled sites keep
the existing replace behavior unchanged.
@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

kangzj added 2 commits July 30, 2026 16:29
Broadens the previous Atomic-only exception to every site: Stats v2 always
adds its own admin menu alongside the existing Stats menu, admin-bar
entries, post-list column, and dashboard widget instead of replacing them,
regardless of host. Drops the now-unused Host::is_woa_site() check from
modules/stats.php and class-jetpack-stats-dashboard-widget.php.
Retype the plugins/jetpack changelog entry as enhancement instead of
bugfix — this is an intentional rollout behavior change, not a defect
fix. Document why test_stats_admin_menu_kept_when_enabled() only tears
down the one action it asserts on.
@kangzj

This comment has been minimized.

@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

@kangzj

kangzj commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Review-cycle summary — 0a3fc094a5 → b17bf0b4a3

3 round(s); CI green; 1 AI reviewer round-trip addressed (no threads to resolve — no inline comments were left).

What changed during the cycle

Commits added:

  • b17bf0b4a3 — Address review: changelog type + test hygiene note (comment #5126405852)
  • f5223dec56 — Stats v2: never replace the legacy Stats menu, on any site

Diff summary: 6 files changed, 35 insertions(+), 146 deletions(-)

Review threads addressed:

Source Comment Resolution
claude[bot] (#5126405852) 3 non-blocking notes: duplicated replace-predicate across files, stats_load() test hygiene, changelog type bugfix vs enhancement Predicate concern resolved outright by f5223dec56 (the replace logic was deleted entirely, not centralized); added a hygiene doc-comment to the test and retyped the changelog to enhancement in b17bf0b4a3
claude[bot] (#5126523064) re-review — verified all three items, no blocking issues, one non-blocking observation (the per-request cache on is_premium_analytics_enabled() is now less load-bearing with fewer callers) No action needed — reviewer explicitly noted nothing to change

Unaddressed (flagged for owner):
None.

CI: all required checks passing (36 pass, 8 skipping as expected for unaffected file types).

@kangzj kangzj added [Status] Needs Team Review Obsolete. Use Needs Review instead. and removed [Status] In Progress labels Jul 30, 2026
@kangzj
kangzj marked this pull request as ready for review July 30, 2026 04:54
@kangzj kangzj removed the [Status] Needs Review This PR is ready for review. label Jul 30, 2026

@chihsuan chihsuan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @kangzj LGTM! 🚢

@kangzj
kangzj merged commit c789318 into trunk Jul 31, 2026
85 checks passed
@kangzj
kangzj deleted the rename/premium-analytics-stats-v2 branch July 31, 2026 01:25
@github-actions github-actions Bot added [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. and removed [Status] In Progress [Status] Needs Team Review Obsolete. Use Needs Review instead. labels Jul 31, 2026
louwie17 added a commit that referenced this pull request Aug 5, 2026
Since #50915 the Stats menu deliberately keeps rendering alongside the
dashboard, so the docblocks describing it as deregistered were wrong.
Reworded to the present tense: the dashboard is the analytics UI, and
Stats remains available for now.

The behaviour is unchanged, but its reason was wrong too. Hiding a link
for a user who cannot open the dashboard is right not because there is no
Stats page to fall back to, but because the dashboard capability maps to
`manage_options` or `view_stats` — a user who fails it cannot open the
Stats page either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB
louwie17 added a commit that referenced this pull request Aug 5, 2026
Since #50915 the Stats menu deliberately keeps rendering alongside the
dashboard, so the docblocks describing it as deregistered were wrong.
Reworded to the present tense: the dashboard is the analytics UI, and
Stats remains available for now.

The behaviour is unchanged, but its reason was wrong too. Hiding a link
for a user who cannot open the dashboard is right not because there is no
Stats page to fall back to, but because the dashboard capability maps to
`manage_options` or `view_stats` — a user who fails it cannot open the
Stats page either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB
louwie17 added a commit that referenced this pull request Aug 5, 2026
Reverts the plan-usage changes: render.tsx, its test, its story, and the
changelog entry that announced the removal.

The link was removed on the grounds that it pointed at a Stats screen
that no longer existed. It does still exist — since #50915 the Stats menu
keeps rendering alongside the dashboard, and following the link on a
flag-on site lands on a working Stats tier picker. Whether the CTA needs
a new home is a question for when the Stats page actually goes away, not
for this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB
louwie17 added a commit that referenced this pull request Aug 5, 2026
…rd (#50926)

* Premium Analytics: point Jetpack's analytics links at the new dashboard

Seven links across Jetpack still pointed at the legacy Stats page. Rather
than spell a URL at each call site, add getAnalyticsUrl() to script-data:
callers describe where they want to go and the helper resolves which
analytics UI the site runs, the page slug, the site and blog identifiers,
the section vocabulary, and the date encoding.

Premium Analytics announces itself by publishing an `analytics` key on
jetpack_admin_js_script_data. Its presence is the branch signal, so no
caller has to ask Jetpack about the feature flag; when absent, the helper
builds the legacy Stats URLs byte-for-byte as before.

Notable details:

- The dashboard keeps its whole router path in a single `p` search param,
  and reads from/to as offset-bearing instants in the site timezone. A
  bare YYYY-MM-DD would be parsed as UTC midnight and land a day early
  west of UTC, so the helper takes calendar days and owns the encoding,
  reading the zone offset at each boundary so a DST-transition day gets
  the right offset on each end.
- At-a-Glance chart bars now open the period the bar stands for. The old
  link ignored the Days/Weeks/Months tab and always deep-linked one day.
- getAnalyticsUrl() returns null when the user lacks the capability to
  open the dashboard, and every call site hides its control rather than
  rendering a dead link.
- The plan-usage upgrade CTA is removed. It pointed at a Stats tier
  purchase screen that was a Calypso route inside the CDN-served Odyssey
  bundle, so it left with that dashboard and has no counterpart here.
- My Jetpack's Stats get_purchase_url() returns null, the base-class
  default, which falls back to the existing /add-stats interstitial.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

* Premium Analytics: narrow the analytics URL helper to what Jetpack links to

Three reductions, all from review feedback:

- Drop the `report` and `video` views. Nothing constructed them; they were
  built from the design doc rather than from a caller, along with a
  13-member report id union and their tests.

- Stop hand-rolling timezone math. `toFixedOffset`, `offsetAt`,
  `offsetToMinutes` and the two-pass DST offset read are replaced by
  date-fns + @date-fns/tz, the same libraries the dashboard's own
  `dateToISOStringWithTZ` uses. The DST-transition test still passes, so
  the bespoke version was only reimplementing the library.

- Stop rebuilding legacy Stats URLs. Those links already worked, so each
  call site keeps its original expression untouched and only routes to
  the dashboard when it has replaced the Stats page. That also restores
  `force_refresh=1` on My Jetpack's card and the prop threading this had
  removed, so the non-dashboard path is now unchanged from trunk rather
  than merely equivalent to it.

`hasAnalyticsDashboard()` is the new gate. It answers a different
question from a null URL: false means "keep your existing link", whereas
null means the dashboard is the analytics UI but this user cannot open
it. Those must not collapse — `stats_admin_menu` is not registered once
the dashboard replaces Stats, so there is no page to fall back to.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

* Premium Analytics: move the analytics URL helper into the Jetpack plugin

The helper was in js-packages/script-data, which meant adding date-fns to
a previously zero-dependency package that 23 projects depend on and that
is autopublished to npm. It only ever had two consumers, and one of them
did not need it at all.

My Jetpack drops it entirely. Its Stats card already receives the
destination as the product's `manage_url`, which `Stats::get_manage_url()`
resolves server-side, so the JS was rebuilding a URL PHP had already
sent. The one thing the URL cannot carry is whether to append
`force_refresh=1` — that is now a `premiumAnalyticsEnabled` entry in
`get_my_jetpack_flags()`, alongside the existing showFullJetpackStatsCard
and isStatsModuleActive flags.

That leaves the Jetpack plugin as the only consumer, so the helper moves
to `_inc/shared/analytics-url.ts`. Its three call sites live in different
trees built by two webpack configs, and the extensions build has no
bare-specifier root, so each imports it by relative path. `_inc/shared/`
is new: `_inc/client`, `modules/` and `extensions/` had no shared JS
between them before this.

script-data goes back to exactly trunk apart from the `analytics` key's
type — the shape of the global is its job, building URLs from it is not.
The jest bootstrap it needed goes away with the test, which now runs
under the plugin's existing client config.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

* Premium Analytics: keep the analytics type out of script-data, simplify the helper

script-data is now byte-identical to trunk. The `analytics` script-data key is
declared where it is read, via module augmentation, so the package that types
the global does not carry a key only the Jetpack plugin uses.

Test simplification (405 -> 227 lines), mostly by table-driving repetitive
cases. One test was worse than redundant: chart-bar-range's "reads the calendar
day in UTC" case monkey-patched Date.prototype.getTimezoneOffset, which the
implementation never calls, so it passed regardless of correctness. Removed,
and timezone independence is now verified by running both date suites under
UTC, Pacific/Kiritimati (+14), Pacific/Niue (-11), America/New_York and
Asia/Kathmandu (+05:45). Added the DST fall-back case, so both a 23-hour and a
25-hour day are covered rather than only spring-forward.

Cleanups from a review pass:
- Drop the `encoded.includes( 'Invalid' )` guard. date-fns `format()` throws a
  RangeError for an unusable zone; it never returns an "Invalid" string, so
  only the catch was ever reachable.
- DASHBOARD_SECTIONS was an identity map keyed by its own union. It is a list
  of accepted slugs, which is all it was doing.
- Inline analyticsPath, whose docblock restated its signature.
- Drop `export` from three types nothing imports, and the WHY repeated three
  times in the same file.
- barLink took siteAdminUrl and siteRawUrl as parameters while already reading
  this.props on its first line.
- format_gmt_offset used floor with a 1e-6 epsilon to guard a rounding case
  that cannot arise for quarter-hour offsets; round() says the same thing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

* Premium Analytics: trim the comment prose on the new code

Roughly half of the new files were comment. Kept the reasoning a reader
cannot infer — why a bare YYYY-MM-DD will not do, why the router's `p`
param is encoded twice, why hasAnalyticsDashboard() differs from a null
URL — and dropped the restatements around it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

* Update pnpm-lock.yaml for the date-fns dependency

Adding date-fns and @date-fns/tz to plugins/jetpack changes peer resolution
for the @wordpress/* packages it shares them with, which pnpm records as new
snapshot keys. Earlier commits added only the importer entries, so the
resolution section was left stale and CI's lock check failed.

Regenerated with `pnpm install --resolution-only`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

* Premium Analytics: correct the docblocks about the Stats page

Since #50915 the Stats menu deliberately keeps rendering alongside the
dashboard, so the docblocks describing it as deregistered were wrong.
Reworded to the present tense: the dashboard is the analytics UI, and
Stats remains available for now.

The behaviour is unchanged, but its reason was wrong too. Hiding a link
for a user who cannot open the dashboard is right not because there is no
Stats page to fall back to, but because the dashboard capability maps to
`manage_options` or `view_stats` — a user who fails it cannot open the
Stats page either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

* Premium Analytics: keep the plan-usage upgrade link

Reverts the plan-usage changes: render.tsx, its test, its story, and the
changelog entry that announced the removal.

The link was removed on the grounds that it pointed at a Stats screen
that no longer existed. It does still exist — since #50915 the Stats menu
keeps rendering alongside the dashboard, and following the link on a
flag-on site lands on a working Stats tier picker. Whether the CTA needs
a new home is a question for when the Stats page actually goes away, not
for this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQezwoePExAo1sc1onk7fB

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Jetpack mu wpcom WordPress.com Features [Package] Premium Analytics [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants