Premium Analytics: add post/page detail traffic view#50096
Conversation
Add the single-resource detail page for an individual post or page: a new /post/$postId route with its own header (Stats breadcrumb + summary card), three tabs (Post traffic / Email opens / Email clicks), the shared date-range and comparison picker, and a customizable per-tab widget grid — mirroring the dashboard while working independently and scoped to one resource. - Extract the dashboard's date-filter controller into a shared useReportDateFilters hook in the routing package and reuse it in both the dashboard and the new page instead of duplicating the staged-search logic. - Seed post_id into the URL search and resolve the current route's search in WidgetRoot so widgets on any route (not only the dashboard at /) receive the date range and single-resource scope.
…dget search per-route Address local review findings on the single-resource scoping: - Add post_id to ReportParams and preserve it in normalizeReportParams so the seeded scope actually reaches widgets via reportParams (it was previously stripped by the normalizer). Typed string|number so the URL string and the existing numeric query-layer usage (statsUtmQuery) both hold; covered by tests. - Resolve WidgetRoot report params from the current matched route (useSearch strict:false) instead of a hardcoded '/', so widgets pinned to options.from='/' also pick up the detail page's date range and post_id. options.from is retained but documented as ignored.
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
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:
If you have questions about anything, reach out in #jetpack-developers for guidance! Premium Analytics 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. |
Code Coverage SummaryThis PR did not change code coverage! That could be good or bad, depending on the situation. Everything covered before, and still is? Great! Nothing was covered before? Not so great. 🤷 |
Replace non-existent design-system tokens flagged by stylelint (plugin-wpds/no-unknown-ds-tokens): --wpds-color-content-neutral-medium/strong → --wpds-color-fg-content-neutral-weak/neutral, and --wpds-dimension-radius-lg/md → --wpds-border-radius-md/sm.
There was a problem hiding this comment.
Pull request overview
Adds a new Premium Analytics SPA route for post/page detail analytics, reusing the dashboard’s date-range + comparison UX and widget customization while scoping widgets via post_id in URL/report params.
Changes:
- Introduce a new
/post/$postIdroute with header breadcrumbs, post summary card, and three section tabs (traffic / email opens / email clicks). - Extract the dashboard date-filter controller into a shared
useReportDateFiltershook and consume it from both dashboard and post detail pages. - Update widget report-param resolution to read search params from the currently matched route (not just
/) and preservepost_idthrough report-param normalization.
Reviewed changes
Copilot reviewed 31 out of 32 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| projects/packages/premium-analytics/routes/post-detail/style-imports.d.ts | Adds TS module declarations for CSS/SCSS imports used by the new route. |
| projects/packages/premium-analytics/routes/post-detail/stage.tsx | Implements the post-detail stage UI (tabs, summary, date filters, widget grid). |
| projects/packages/premium-analytics/routes/post-detail/stage.module.scss | Styles layout spacing/padding for the post-detail page. |
| projects/packages/premium-analytics/routes/post-detail/route.ts | Adds route guards + initial URL seeding (dates + post_id) and widgetModule entity bootstrap. |
| projects/packages/premium-analytics/routes/post-detail/package.json | Declares the new route package, dependencies, and route mount path. |
| projects/packages/premium-analytics/routes/post-detail/hooks/use-post-summary.ts | Fetches Stats post info + core post entity data for the header summary card. |
| projects/packages/premium-analytics/routes/post-detail/hooks/use-post-detail-tab-layout.ts | Persists per-tab widget layouts for the post-detail page via preferences. |
| projects/packages/premium-analytics/routes/post-detail/hooks/use-active-tab.ts | Drives active tab via ?section= using staged search. |
| projects/packages/premium-analytics/routes/post-detail/hooks/index.ts | Exports post-detail hooks. |
| projects/packages/premium-analytics/routes/post-detail/hooks/constants.ts | Defines preferences scope/key for post-detail layouts. |
| projects/packages/premium-analytics/routes/post-detail/config/tabs.ts | Defines post-detail tab IDs and translated labels. |
| projects/packages/premium-analytics/routes/post-detail/config/tabs.test.ts | Adds unit tests for tab definitions and URL resolution behavior. |
| projects/packages/premium-analytics/routes/post-detail/config/tab-layouts.ts | Adds runtime validator for persisted tab layout map shape. |
| projects/packages/premium-analytics/routes/post-detail/config/index.ts | Re-exports post-detail config helpers/types. |
| projects/packages/premium-analytics/routes/post-detail/components/stats-breadcrumbs/stats-breadcrumbs.tsx | Renders “Stats / ” breadcrumb header UI. |
| projects/packages/premium-analytics/routes/post-detail/components/stats-breadcrumbs/stats-breadcrumbs.module.scss | Styles breadcrumbs. |
| projects/packages/premium-analytics/routes/post-detail/components/post-summary-card/post-summary-card.tsx | Renders post/page summary card (type, title, publish date, featured image). |
| projects/packages/premium-analytics/routes/post-detail/components/post-summary-card/post-summary-card.module.scss | Styles the post summary card. |
| projects/packages/premium-analytics/routes/post-detail/components/post-detail-tabs/post-detail-tabs.tsx | Presentational wrapper for the tab bar and shared Tabs.Root. |
| projects/packages/premium-analytics/routes/post-detail/components/post-detail-tabs/post-detail-tabs.module.scss | Styles the tab bar and active-state colors. |
| projects/packages/premium-analytics/routes/post-detail/components/index.ts | Exports post-detail components. |
| projects/packages/premium-analytics/routes/dashboard/stage.tsx | Refactors dashboard to use useReportDateFilters instead of inlined staged-search logic. |
| projects/packages/premium-analytics/packages/widgets-toolkit/src/components/widget-root/widget-root.tsx | Resolves report params from the current matched route search (strict:false) and deprecates options.from. |
| projects/packages/premium-analytics/packages/widgets-toolkit/src/components/widget-root/README.md | Documents options.from as deprecated/ignored. |
| projects/packages/premium-analytics/packages/routing/src/index.ts | Exports useReportDateFilters from routing package entrypoint. |
| projects/packages/premium-analytics/packages/routing/src/hooks/use-report-date-filters/use-report-date-filters.tsx | Adds shared date filter controller hook extracted from the dashboard. |
| projects/packages/premium-analytics/packages/routing/src/hooks/use-report-date-filters/index.ts | Barrel export for useReportDateFilters. |
| projects/packages/premium-analytics/packages/routing/src/hooks/index.ts | Re-exports useReportDateFilters alongside existing hooks. |
| projects/packages/premium-analytics/packages/routing/package.json | Adds dependencies needed by the new routing hook (core-data/data/date-fns/react). |
| projects/packages/premium-analytics/packages/data/src/utils/search.ts | Extends ReportParams and normalization to preserve post_id. |
| projects/packages/premium-analytics/packages/data/src/utils/tests/normalize-report-params.test.ts | Adds tests ensuring post_id survives normalization. |
| projects/packages/premium-analytics/changelog/add-WOOA7S-1622-post-detail-page | Adds changelog entry for the new post detail page feature. |
- Validate post_id is a positive integer both at the route seed (so /post/foo never puts a malformed post_id in the URL) and in normalizeReportParams (defense for hand-edited deep links), coercing it to a number and dropping non-numeric/zero/negative values (comments #3502774220, #3502774234). - Scope usePostSummary's Stats query to the 'post' field since the header only needs title/type (comment #3502774246).
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Claude finished @kangzj's task in 1m 8s —— View job Re-review —
|
🤖 Review-cycle summary —
|
| Source | Comment | Resolution |
|---|---|---|
| Copilot | normalizeReportParams doesn't validate post_id |
Coerce to a positive integer, drop non-numeric/zero/negative (08c3b5e) |
| Copilot | route.ts seeds post_id without validation |
Only seed when the path param is a positive integer; /post/foo seeds nothing (08c3b5e) |
| Copilot | usePostSummary fetches full payload |
Scope the Stats query to fields: [ 'post' ] (08c3b5e) |
| kangzj (owner) | Should post_id be a separate type? |
Kept on ReportParams (a URL param that must flow through WidgetRoot), now validated; rationale in-thread |
CI: all required checks passing (52 passed, 0 failed).
Part of WOOA7S-1622
Why
Premium Analytics could only show site-wide stats. There was no way to drill into a single post or page. This adds a dedicated detail page for one post/page — its own traffic, email opens, and email clicks — so authors can see how an individual piece of content performs without leaving the analytics dashboard.
Proposed changes
/post/$postIdSPA route with its own header — aStats / <post title>breadcrumb (linking back to the dashboard) and a summary card (type badge, title, published date, featured image).?section=.useReportDateFiltershook in theroutingpackage and consume it from both the dashboard and the new page, instead of duplicating the staged-search logic.post_idinto the URL, carry it throughReportParams/normalizeReportParams, and resolve widget report params from the current matched route (so widgets pick up the date range andpost_idon any route, not only the dashboard at/).Out of scope (tracked separately under WOOA7S-1458): the post-scoped Performance / Latest comments / Latest likes / UTM widgets shown in the design. This PR ships the page framework; those widgets land in follow-ups and drop straight into the tabs.
Screenshots
Captured on a local docker env. It runs in offline mode (no live WordPress.com data), so widgets are empty and the title is blank; the post-scoped widgets and their data arrive in follow-ups.
Post detail page — the
Statsbreadcrumb, the three tabs, the post summary card, the shared date-range + "Compare to" picker, and the customizable widget grid.Widget customization — the "Add widget" inserter on the page.
Verification
Built and exercised end-to-end in a local WordPress env (
?page=jetpack-premium-analytics-wp-admin&p=/post/<id>):Manual browser testing
Automated checks
Related product discussion/links
Does this pull request change what data or activity we track or use?
No. It surfaces existing Stats data scoped to a single post/page; no new data is tracked or collected.
Testing instructions
jetpack build packages/premium-analytics(orpnpm run buildinsideprojects/packages/premium-analytics), then build the plugin:jetpack build plugins/premium-analytics.admin.php?page=jetpack-premium-analytics-wp-admin&p=/post/<POST_ID>(use a published post/page ID).Stats / <post title>(breadcrumb) plus a summary card (type, title, published date, featured image). "Stats" links back to the dashboard.post_idpresent in the URL/report params).&p=/) still renders and behaves as before.