Skip to content

Premium Analytics: add Regions to the Top locations "View by" control - #51267

Merged
kangzj merged 6 commits into
trunkfrom
echo/wooa7s-1940-locations-region-dropdown
Aug 17, 2026
Merged

kangzj merged 6 commits into
trunkfrom
echo/wooa7s-1940-locations-region-dropdown

Conversation

@kangzj

@kangzj kangzj commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Fixes WOOA7S-1940

Why

Site owners could see which countries their visitors came from, and which cities — but not which regions, unless they clicked into one country at a time and read its regions in isolation. There was no way to ask "which regions send me the most traffic overall". The full Locations report has had a Regions tab all along; the dashboard widget just never offered it. Now it does.

Proposed changes

  • Add Regions to the Top locations widget's "View by" control, between Countries and Cities.
  • Regions mode is worldwide, like Cities: the leaderboard lists the top regions across every country, each with its country's flag.
  • The map summarises those regions back up to their country — Google GeoChart can't place sub-country rows on the world map. Cities mode already did this; the same path now serves both.
  • Switching to Regions (or Cities) clears an active country drill-down, so a country selected in Countries mode can't linger in a mode that has no way to clear it.
  • "View all" from Regions mode opens the Locations report on its Regions tab, matching what Countries and Cities already did.

Countries mode, its click-through drill-down into one country's regions, and the province map for the selected country are all unchanged.

Screenshots

The "View by" control, before and after — same widget, same data, same scroll position:

Top locations "View by" dropdown, before and after

Regions selected — worldwide regions in the leaderboard with their country flags, summarised by country on the map:

Top locations widget in Regions mode

Related product discussion/links

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

No. Regions mode reads the same stats/location-views/{geoMode} endpoint the widget already used for the country drill-down, and the Locations report already queries it unfiltered for its Regions tab.

Testing instructions

Acceptance criteria from the issue, as a checklist:

  • Go to Jetpack → Stats → Traffic on a Jetpack-connected site with location data.
  • Open the Top locations widget's "View by" dropdown — it lists Countries, Regions, Cities. Before this change only Countries and Cities were there.
  • Select Regions. The leaderboard lists regions from across the world (not one country's), each with its country flag, and the map highlights the countries those regions belong to.
  • Click View all — the Locations report opens on its Regions tab.
  • Switch back to Countries and click a country row. It still drills into that country's regions, still draws the province map, and the "All locations" back link still returns to the country list.
  • While drilled into a country, switch to Regions: the drill-down clears and the worldwide region list appears.
  • Cities is unchanged — city rows in the leaderboard, summarised by country on the map, "View all" opening the Cities tab.

The screenshots above come from a local docker site whose stats/location-views responses were mocked, since an offline-mode site has no live Stats data. Storybook covers the same states without a WordPress install: Packages/Premium Analytics/Widgets/Locations now has a RegionsMode story alongside Default and CitiesMode.

The second observation in the issue — "the Top platforms widget is missing platform distribution" — was checked separately and is not the same issue. Its dropdown offers Browser and OS and both render correctly (Windows / macOS / Android / iOS / Linux under OS). The Desktop / Mobile / Tablet split lives in the separate Devices widget. Nothing to fix there; if that split should also appear inside Top platforms, that is a product decision worth its own issue.

The widget's dropdown offered only Countries and Cities, so a site owner could
reach region data only by drilling into one country at a time — while the
Locations report has had a Regions tab all along.

Regions mode is worldwide, like Cities: the leaderboard lists regions and the
map sums them back up to their country, since Google GeoChart cannot place
sub-country rows on the world map.
@kangzj
kangzj requested a review from a team as a code owner August 14, 2026 01:13
@kangzj kangzj added Enhancement Changes to an existing feature — removing, adding, or changing parts of it [Status] Needs Review This PR is ready for review. labels Aug 14, 2026
@kangzj kangzj self-assigned this Aug 14, 2026
@kangzj kangzj added [Status] In Progress and removed [Status] Needs Review This PR is ready for review. labels Aug 14, 2026
@kangzj
kangzj marked this pull request as draft August 14, 2026 01:14
@github-actions

github-actions Bot commented Aug 14, 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 echo/wooa7s-1940-locations-region-dropdown branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack echo/wooa7s-1940-locations-region-dropdown
bin/jetpack-downloader test jetpack-mu-wpcom-plugin echo/wooa7s-1940-locations-region-dropdown

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

@kangzj

This comment has been minimized.

@github-actions

github-actions Bot commented Aug 14, 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!


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.

@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

This comment has been minimized.

@jp-launch-control

jp-launch-control Bot commented Aug 14, 2026 •

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/packages/premium-analytics/widgets/locations/render.tsx 61/85 (71.76%) 19.96% -16 💚

Full summary · PHP report · JS report

…reset

- REPORT_SECTIONS values are typed to the report's own tab ids so a slug typo
  fails the build; ReportLink takes a bare string and would not.
- Fall back to the Countries tab when a persisted layout carries a granularity
  outside the union.
- Test the round trip the reset actually guards: drill into a country, switch to
  Regions, and come back to Countries listing every country again.
- Fix an it.each title whose placeholders read in the opposite order to its tuple.
@kangzj

This comment has been minimized.

@kangzj

This comment has been minimized.

@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

This comment has been minimized.

The report-link fallback only covered one of the two consumers: the same
unvalidated value became the geoMode path segment, so a stale layout would
still request stats/location-views/<unknown> and render an error under a link
that had quietly fallen back to Countries. Normalizing once covers both and
lets the fallback go.

Also type the test's hook fixture off the hook itself, so a new LocationView
field breaks the test rather than being cast away, and assert the map still
renders in Regions mode.
@kangzj

This comment has been minimized.

@kangzj

This comment has been minimized.

@claude

This comment has been minimized.

`in` also accepts inherited keys, so `toString` would have passed
normalization and reached the endpoint as a path segment — the same failure the
normalization was added to close.

Also correct a fixture comment: the typing protects the row literals passed to
mockReturnValue, not the empty-data constant it sat above.
@kangzj

This comment has been minimized.

@kangzj

kangzj commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Review-cycle summary — 962db00aa4 → 7776c285ed

3 rounds; CI green (62 passing, 0 failing); 8 findings from 2 AI reviewers triaged, 6 applied and 2 declined with reasons.

What changed during the cycle

Commits added:

  • 7776c285ed — Address review: use an own-property check for the stored granularity
  • 2c0155afe1 — Address review: normalize the stored granularity at the widget boundary
  • 04566ecdac — Address review: type the report-section map and cover the drill-down reset

Diff summary: 2 files changed, 76 insertions(+), 7 deletions(-)

Findings addressed:

Round Source Finding Resolution
1 claude it.each title placeholders read in the opposite order to its tuple Reworded — 04566ecdac
1 claude No test for the behaviour the drill-down reset guards Added the round-trip test (drill in → Regions → back to Countries); verified it fails against the old guard. The originally-suggested assertion passes either way, since activeSelectedCountry masking already blanks the filter — 04566ecdac
1 claude REPORT_SECTIONS lookup not total at runtime Typed the values as the report's tab ids so a slug typo fails the build; added a fallback — 04566ecdac
2 claude The fallback covered only one of two consumers Correct: the same value became the stats/location-views/{geoMode} path segment, so a stale layout rendered an error state under a link that had silently fallen back. Normalized once at the boundary; fallback dropped as redundant — 2c0155afe1
2 claude as unknown as cast opted the test fixture out of type checking Typed off the hook's own return type — 2c0155afe1
2 claude geo-chart test id never queried Asserted in the drill-down test — 2c0155afe1
3 claude in also matches inherited keys Correct, and it reopened the same hole: 'toString' in REPORT_SECTIONS is true. Swapped for Object.prototype.hasOwnProperty.call — 7776c285ed
3 claude Fixture comment described protection the empty-data constant can't provide Reworded to name the row literals it actually guards — 7776c285ed

Declined:

  • Plugin changelog entries alongside the package entry. Every widget change in this package ships a package-only entry, and plugins/premium-analytics is pre-release. claude reached the same conclusion and raised it only to make the call deliberate.
  • Regions map can look sparse. Real, but Cities mode already makes the identical top-N-summarised-to-country tradeoff, and map and leaderboard describe the same visible rows. A design call across both modes rather than a divergence to introduce here.

copilot-swe-agent returned no actionable findings in either round.

Unaddressed (flagged for owner): none.

Verification: 7/7 locations tests, package typecheck and ESLint clean, and all three modes driven in a live dashboard after each rebuild — each renders and each "View all" opens its matching report tab.

@kangzj kangzj added [Status] Needs Team Review Obsolete. Use Needs Review instead. and removed [Status] In Progress labels Aug 14, 2026
@kangzj
kangzj marked this pull request as ready for review August 14, 2026 02:22
};

function getGeoChartCountryId( countryCode: string ): string {
if ( countryCode.toUpperCase() === 'TW' ) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

hum why would we need this special handling here 🤔

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.

Looked at it. I think this line does nothing now. It came in with #50251 the "Avoid unsupported Taiwan map" commit.

The actual fix turned out to be runtimeUnsupportedProvinceMapCountries. Worth deleting in a follow-up rather than here, keep the .toUpperCase() though.

cc @dognose24 for confirming.

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.

Confirmed — that line came out of the TW "Requested map does not exist" fight, and you're right that the actual fix was runtimeUnsupportedProvinceMapCountries; the province-map error happens on the region: 'TW' + resolution: 'provinces' path, which this row-value mapping never touches. One nuance before deleting: it does change the world-map datatable value from 'TW' to 'Taiwan'. GeoChart's regions mode documents ISO alpha-2 as accepted, so the bare code should highlight the same — worth a quick check against the Cities-mode story (its mock has TW rows) when the follow-up removes it. Keeping .toUpperCase() 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Leaving the TW → Taiwan mapping in place here as agreed, .toUpperCase() included. Happy to open the follow-up to remove it, with the Cities-mode story check against the TW rows as the verification step.

@kangzj
kangzj requested a review from chihsuan August 14, 2026 03:22
chihsuan
chihsuan previously approved these changes Aug 14, 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. Confirmed it works as expected.

Just nits inline, nothing blocking. 🚀

};

function getGeoChartCountryId( countryCode: string ): string {
if ( countryCode.toUpperCase() === 'TW' ) {

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.

Looked at it. I think this line does nothing now. It came in with #50251 the "Avoid unsupported Taiwan map" commit.

The actual fix turned out to be runtimeUnsupportedProvinceMapCountries. Worth deleting in a follow-up rather than here, keep the .toUpperCase() though.

cc @dognose24 for confirming.

Comment thread projects/packages/premium-analytics/widgets/locations/render.tsx Outdated
A package-only entry reaches the package CHANGELOG and nowhere else, so a
user-visible control gaining an option stays invisible to the people who read
the plugin changelog.

@dognose24 dognose24 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.

Read through the widget and the report wiring — the regions tab is already registered, the unfiltered request shape is right, and the stale-attribute normalization is a nice touch. Three small notes inline, none blocking.

Comment thread projects/packages/premium-analytics/widgets/locations/render.tsx
@dognose24

Copy link
Copy Markdown
Contributor

Heads-up: #51312 (WOOA7S-1922 — the earlier card for the same parity gap) implements the same Regions view and conflicts with this on five files. Suggest syncing with @Nikschavan — one workable split is this PR landing the core view and #51312 shrinking to the per-country tooltip it adds on top.

Also, verified while comparing the two: the map rollup here sums the capped rows (maxRows trims to 10 in the data layer), so a country's colour reflects only its regions that made the global top 10 — same pre-existing issue as Cities mode. The email-breakdown mapRows={ allRows } pattern is the precedent if you want to fix it in this PR; otherwise worth a card so it doesn't get lost.

…ilter from it

Also aligns the package changelog prefix with the card name and drops the
literal 'undefined' from the granularity test titles.
@kangzj
kangzj merged commit 7aafcc6 into trunk Aug 17, 2026
109 of 110 checks passed
@kangzj
kangzj deleted the echo/wooa7s-1940-locations-region-dropdown branch August 17, 2026 22:02
@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] Needs Team Review Obsolete. Use Needs Review instead. labels Aug 17, 2026
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 [Package] Premium Analytics [Plugin] Premium Analytics [Status] UI Changes Add this to PRs that change the UI so documentation can be updated.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants