Commit 785398b
Premium Analytics: add a Popular post widget and share the post highlight card (#50931)
* Premium Analytics: add a Popular post widget and share the post highlight card
Adds the Insights "Most popular post" module as `jpa/popular-post`: the
site's most-viewed post for the dashboard's selected date range, with its
publish date and the same three metric tiles as Latest post. Unlike Latest
post it is period-scoped, reading `reportParams` from the widget root
context, so changing the date range changes both the winning post and its
view count. Views come from `stats/top-posts` for the period; likes and
comments come from `stats/post/{id}`, which takes no date range, so those
two tiles carry an all-time aggregation note instead of implying a period
number.
Latest post's presentational card moves to `PostHighlightCard` in
widgets-toolkit so both widgets render one card shape, and the card now
adapts to the dashboard cell with a single container-query breakpoint:
width-2 and wider cells get the two-column layout from the design (text
left, metric row anchored to the bottom, rounded near-square featured
image right), while width-1 cells drop the image and wrap the metric row.
The publish line copy now matches the prototype ("Post published on
<date>").
WOOA7S-1787
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: make the post highlight card height-aware
The card's size ladder branched on width only, so a cell that was wide
enough for the two-column layout but short could not fit its content. The
metric row was pinned to the end of an over-tall column and `overflow:
hidden` on the root silently clipped it: at a 736x86 body the row's values
sat 38px below the clip boundary, leaving the labels cut mid-line, and at
331x86 the labels rendered cleanly with no values under them at all.
Rebuilt against the design prototype, which resolves `wide = inline-size
>= 520px` and `tall = block-size >= 300px` and ships `--wide-tall` /
`--wide-short` / `--narrow-short` treatments. The card now declares its
own named size container -- the shared `widget` container is
`container-type: inline-size` and cannot answer block-axis queries -- and
queries both axes, following the precedent in `widget-state.module.scss`.
The clipping is fixed structurally rather than by moving a breakpoint:
`.metrics` is `flex-shrink: 0` and `.header` is the flexible, clipping
box, so the headline gives up space while the metric row keeps its full
size. A label can no longer be shown without its value at any geometry.
Below the height where the publish line also fits, it is dropped outright
instead of being clipped to a sliver.
Both widgets gain ShortCell and ShortNarrowCell dashboard stories so a
height regression is visible in review.
WOOA7S-1787
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: address Popular post review feedback
Read every displayed metric from `stats/post`, so the three tiles share one
all-time window instead of pairing range-scoped views with lifetime likes and
comments. The date range's only job is now picking the winner, which also
matches the sibling Latest post widget that shares this card.
Consume metrics only from a response that identifies the current post. The
Stats query carries the previous key's payload over through `placeholderData`
while the content query deliberately does not, so a winner change could render
the new post's title beside the previous post's engagement.
Drop the comparison fields from the top-posts request: they triggered a second
report fetch for a window this widget never renders.
Document the `max` trade-off that can hide a qualifying post on a page-heavy
site.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: address Chi's post widget review feedback
Show an unread metric as a dash rather than as zero. The Stats post endpoint
can fail on its own — it 403s on a private site — and zeroing there rendered a
post with 12 likes as "Likes 0", which is a wrong number rather than a missing
one. Applies to Latest post too, which shares the card and had the same gap.
Stop hiding a report failure behind stale rows. `placeholderData` only applies
while a query is pending, so rows that survive an error are the last successful
data — a failed background refetch. Gating on `! topRow` / `! latestPost` hid
exactly that: stale numbers, no error, no Retry.
Correct the story docblocks that still described a 432px breakpoint; the card
resolves wide at 520px and tall at 300px.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: trim the post widget doc blocks
Compress the comments added over the review rounds: keep the non-obvious
rationale, drop the restated-code prose and the multi-paragraph explanations.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: import post highlight card UI from externals
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: fix the post widget Storybook states
The stats/post mock returned a fixture with a hardcoded post ID for every
requested post, so the card could never attribute the metrics to the current
winner and sat in its skeleton forever. The mock now echoes the ID it was asked
for, which is what the real endpoint does.
Move the Empty story off `last-365-days`: it resolves to the same dates as
ErrorRetryable's `last-12-months` most years, so the two shared a query key and
Empty's cached result won.
Normalize `comment_count` in `sanitizeStatsPostResponse` instead of in each
consumer, removing three copies of the same coercion.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: link the Popular post title to the post detail page
Matches Latest post, which trunk moved onto the internal detail route. Both
widgets now carry the dashboard's window into the detail page, and the card
still falls back to the published post when there is no post ID.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: give the Popular post stories a router
The card's title now renders a router-backed Link when it has a post ID, so
the close-up stories need the same `withStoryRouter` decorator the sibling
post widgets already use.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: declare the post widgets' real dependencies
Popular post imports `pickReportDateParams` and `useMemo` but declared neither,
building only because hoisting happened to provide them. Latest post gained the
same `useMemo` import, and no longer uses `date-fns` or `externals` since the
shared card took over its rendering.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: sync the Popular post docs with its behaviour
The widget reads every metric from `stats/post`, so the date range picks the
winner rather than scoping the view count. The widget definition and the
Storybook descriptions still described the earlier period-scoped views.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
* Premium Analytics: move the post highlight card onto the theme 1.0 tokens
Trunk's `@wordpress/*` update renamed the font-weight tokens (medium ->
emphasis, regular -> default). The shared card still used the old names, which
resolve to nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HAX3YkQxDLLXhKXjft6qU2
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Committed via a GitHub action: https://github.com/Automattic/jetpack/actions/runs/31017284317
Upstream-Ref: Automattic/jetpack@591670e1 parent 3cb07a1 commit 785398b
20 files changed
Lines changed: 47 additions & 13 deletions
File tree
- build
- modules
- data
- widgets-toolkit
- widgets
- latest-post
- popular-post
- post-detail-highlights
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| 59 | + | |
59 | 60 | | |
60 | 61 | | |
61 | 62 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
46 | 49 | | |
47 | 50 | | |
48 | 51 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
10 | | - | |
11 | 9 | | |
12 | 10 | | |
13 | 11 | | |
| |||
0 commit comments