Skip to content

Premium Analytics: add Stats traffic normalizers#49776

Open
kangzj wants to merge 3 commits into
split/stats-proxy-foundationfrom
split/stats-core-normalizers
Open

Premium Analytics: add Stats traffic normalizers#49776
kangzj wants to merge 3 commits into
split/stats-proxy-foundationfrom
split/stats-core-normalizers

Conversation

@kangzj

@kangzj kangzj commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #

Proposed changes

  • Add the first Stats response normalizers for traffic-style reports: top posts, referrers, clicks, search terms, file downloads, authors, locations, and video plays.
  • Export the normalized Stats report/item types from the package data layer.
  • Add fixture-based tests for representative response shapes with nested rows and numeric string coercion.

What changed and why

This is PR 2 in the split from #49773, stacked on #49775. It keeps the data-shaping layer separate from the query/hook API so reviewers can validate the normalized report contract before endpoint wiring is added.

The normalizers convert Jetpack Stats proxy responses into the existing Premium Analytics-style report shape: a numeric summary plus data rows with shared keys like label, value, children, link, and action metadata. That keeps Stats widgets and dashboards from needing endpoint-specific response handling.

Non-test/support implementation size: 344 lines including changelog and exports.

Related product discussion/links

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

No.

Testing instructions

  • Run pnpm --dir projects/packages/premium-analytics test.
  • Run pnpm --dir projects/packages/premium-analytics typecheck.
  • Run pnpm --dir projects/packages/premium-analytics build.

@kangzj kangzj added Enhancement Changes to an existing feature — removing, adding, or changing parts of it [Feature] Stats Data Feature that enables users to track their site's traffic and gain insights on popular content. [Status] Needs Review This PR is ready for review. [Package] Premium Analytics labels Jun 19, 2026
@kangzj kangzj self-assigned this Jun 19, 2026
@github-actions

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!

@jp-launch-control

jp-launch-control Bot commented Jun 19, 2026

Copy link
Copy Markdown

Code Coverage Summary

No summary data is available for parent commit b8db15a, so cannot calculate coverage changes. 😴

If that commit is a feature branch rather than a trunk commit, this is expected. Otherwise, this should be updated once coverage for b8db15a is available.

Full summary · PHP report

@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

@kangzj

This comment has been minimized.

This comment has been minimized.

@kangzj kangzj added [Status] Needs Team Review Obsolete. Use Needs Review instead. and removed [Status] Needs Review This PR is ready for review. labels Jun 19, 2026
@kangzj kangzj force-pushed the split/stats-core-normalizers branch from 35c63e7 to da463c7 Compare June 19, 2026 04:43
@kangzj

This comment has been minimized.

@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

This comment has been minimized.

@kangzj

This comment has been minimized.

@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

@kangzj

kangzj commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Review loop clear for current head e9be8ec1f3. No required checks are reported for this stacked branch. Local validation after the latest stack rebase passed: pnpm --dir projects/packages/premium-analytics test, typecheck, and build.

@louwie17 louwie17 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I left a couple thoughts, a bit around simplification. Also that we may want to change the structure of the normalized data a bit to help simplify the normalization for each endpoint.
For example each item relies on views and a label most of the other things could be considered meta.

Comment on lines +106 to +108
const items = query?.summarize
? asArray< AnyRecord >( asRecord( response ).summary?.postviews )
: asArray< AnyRecord >( bucket.postviews );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This seems a bit redundant given getStatsBucket, as it basically does the same thing as far as I am understanding.
This is duplicated in each function, so maybe we can clean this up. Also asRecord sounds a bit confusing. Do we need this? Can't we use response?.<key> in that case?

summary: numericSummary( {
total:
bucket.total ??
groups.reduce( ( total, item ) => total + safeParseFloat( item.total ?? item.views ), 0 ),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We are doing the reduce in a lot of places as well to count the total amount. Maybe a function countTotalByKey or something would help make this a bit more readable.

Also what does numericSummary exactly do? it seems like it enforces the summary to be a float? Maybe we can highlight that in the function call as well.
Also curious in what scenarios we run into either a string or number that it has to be explicitly converted. There seem to be a lot of handling of potential edge cases, but not sure if they are real?

actions?: StatsItemAction[];
actionMenu?: number;
[ key: string ]: unknown;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It may be helpful to split this up a bit into data that is shown in a chart ( labels, values ) and things that may be required for adding custom labels or additional data points, that could be considered meta data that is more specific to the widget it-self.
This may help simplify the parsing below as well.
This is just a thought, I did not double check if that seems reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Changes to an existing feature — removing, adding, or changing parts of it [Feature] Stats Data Feature that enables users to track their site's traffic and gain insights on popular content. [Package] Premium Analytics [Status] Needs Team Review Obsolete. Use Needs Review instead.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants