Commit a38e1c2
authored
Stats: show a pricing grid instead of the dashboard for new sites without a plan (#113366)
* Stats: show a pricing grid instead of the dashboard for new sites without a plan
In Odyssey, the traffic page controller is wrapped with a gate: a site that
first connected on or after 2026-08-07 and holds no Stats plan sees a Free vs
Paid choice in place of the dashboard. Picking either plan reveals the
dashboard immediately and records a dismissal through the existing stats
notices endpoint (new `pricing_grid` id), so the grid stays away on later
visits. The id defaults to hidden until the server reports it — the same
ship-ahead treatment `free_site_upgrade` gets — so the grid cannot render
without a working dismissal round-trip.
The grid replicates the Jetpack Search upsell's PricingTable rendering — DOM
structure and styles ported from @automattic/jetpack-components, which Calypso
does not ship — using @wordpress/components primitives, with colors mapped to
the studio palette tokens the jetpack theme is built from.
The connection date reads the `created_at` site option: for a Jetpack site
that is the wpcom shadow blog's `wp_blogs.registered`, which matches the
first-connection moment when registration created the row; a reused
pre-existing row keeps its older date, so the check can only withhold the grid
from a new connection, never show it to an established site. Eligibility
defers to `useStatsPurchases`, so bundled plans (Complete, Growth, Business)
count as having Stats. The date check is synchronous against site options, so
established sites never wait on the purchase and notice lookups; the grid
component itself stays in an async chunk. Calypso is untouched apart from the
shared component directory.
* Stats: give the pricing grid top priority among dashboard notices
While the grid is undismissed it replaces the dashboard outright, so no other
dashboard notice should fire alongside it.
* Stats pricing grid: record dismissal reliably from both CTAs
The wp-admin shim intercepts anchor clicks inside #wpcom with a jQuery handler
registered before React mounts, so an onClick on a link Button never ran and
clicking Get Paid Stats never recorded the dismissal. The paid CTA now
navigates programmatically after dismissing.
The dismissal mutation also never touched the notices query cache, so
returning from the purchase page via 'I will do it later' re-rendered the grid
from the stale cached visibility. Dismissing now patches the cached notices in
place, which the gate re-reads on SPA route changes.
Verified end to end in Odyssey on a local Jetpack site: both CTAs POST the
dismissal, 'I will do it later' lands on the dashboard, and the choice
survives hard reloads.
* Stats: keep the pricing grid out of the notices conflict group
Conflict suppression runs on the server-reported visibility, not on whether
the grid actually displays, and the server reports `pricing_grid` as visible
until a dismissal is recorded. Sites that never meet the grid — everything
connected before launch, everything holding a plan — would therefore have
every other dashboard notice (GDPR consent, purchase-success, the upsells,
tier upgrade) permanently suppressed.
The grid still trumps every notice, structurally: it replaces the whole
dashboard, so StatsNotices never mounts alongside it.
* Stats pricing grid: dismiss on a plan decision, not on reaching checkout
Clicking Get Paid Stats no longer dismisses the grid — merely reaching the
purchase page is not a plan choice, so an abandoned checkout brings the
visitor back to the grid to choose again. The decisions that dismiss are
'Start for free' on the grid and 'I will do it later' on the purchase page
(both the commercial and PWYW flows, keyed off the pricing-grid referrer).
Completing a purchase needs no dismissal: holding a plan makes the site
ineligible for the grid.
The dismissal (mutation + notices-cache patch) moves into a shared
useDismissPricingGrid hook so all call sites stay in sync.
* Stats pricing grid: dismiss on 'I will do it later' regardless of referrer
Anyone clicking the skip button has seen the full paid pitch and deferred, so
the grid shouldn't take over the dashboard afterwards no matter how they
reached the purchase page. On sites where the grid never shows the dismissal
is a harmless no-op.1 parent 4a9ec74 commit a38e1c2
10 files changed
Lines changed: 818 additions & 2 deletions
File tree
- apps/odyssey-stats/src
- client/my-sites/stats
- hooks
- pricing-grid
- hooks
- stats-purchase
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
64 | | - | |
65 | | - | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
66 | 69 | | |
67 | 70 | | |
68 | 71 | | |
| |||
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
15 | 19 | | |
16 | 20 | | |
17 | 21 | | |
| |||
31 | 35 | | |
32 | 36 | | |
33 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
34 | 43 | | |
35 | 44 | | |
36 | 45 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
Loading
Lines changed: 33 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
Lines changed: 40 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
0 commit comments