Newsletter: port Subscribers DataViews onto the modernization chassis#48581
Newsletter: port Subscribers DataViews onto the modernization chassis#48581
Conversation
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
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! Jetpack 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 Summary2 files are newly checked for coverage.
Full summary · PHP report · JS report If appropriate, add one of these labels to override the failing coverage check:
Covered by non-unit tests
|
126ad0b to
1eb4e7c
Compare
The Gravatar component (with hovercard support, SHA-256 hashing, and a configurable defaultImage) moves into @automattic/jetpack-components exposed at the `./gravatar` subpath. Forms switches to it; the local copy in `projects/packages/forms/src/dashboard/components/gravatar/` is removed and the `@gravatar-com/hovercards` and `js-sha256` deps move with it. Sets up Newsletter's Subscribers port to consume the same shared component. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds `WPCOM_REST_API_V2_Endpoint_Subscribers_List` registering
`/wpcom/v2/subscribers/{list,individual,totals,stats,add,remove,products,comp,remove-comp}`.
Each route proxies to the corresponding WP.com endpoint via
`Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user`.
The wp-admin Newsletter page (next commit) consumes these endpoints to
render the Subscribers DataViews table and per-subscriber actions on
Jetpack-connected self-hosted sites. Glob-loaded by
`load-wpcom-endpoints.php`, so no loader changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ports the non-rendering plumbing from #48420's Phase 2 into `_inc/subscribers/`: - `data/api.ts` + `data/types.ts` — REST client + DataViews/API types. - React Query hooks for list, individual, totals, stats, add, remove, comp / remove-comp, and memberships products. - `lib/` helpers: CSV parsing, DataViews i18n, site context, subscriber helpers, subscription plans + status, Tracks events, and the DataViews `View` <-> URL state hook. No UI yet. The list, cells, modals, and detail pane (next commit) consume these hooks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops in the rendering layer ported from #48420: - `subscribers-data-views.tsx` — the table/list with fields, filters, pagination, row actions, and bulk actions. - `subscribers-body.tsx` — selection, modal orchestration, and the `<SubscribersDataViews>` mount. - `cells/{subscriber-identity,subscription-status-cell,subscription-type-cell}` — column renderers (identity uses the shared `Gravatar`). - `detail/subscriber-detail-content.tsx` — sliding inspector content with joined date, status, and email engagement stats. - `modals/{add-subscribers,comp,remove-comp,unsubscribe}-modal` — row + bulk action dialogs. - `header-actions.tsx`, `empty-state.tsx`, `jetpack-logo.tsx` — page chrome accents. Not yet mounted; the next commit wires `<SubscribersBody />` into the route Stage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The page-shell scaffolded in #48574 now renders the Subscribers list: the Stage wraps `<SubscribersBody>` (selection, modals, header actions) inside the existing `<Page>` chrome and `QueryClientProvider`, adds the page subtitle, and pulls in `route.scss` for the identity cell, inspector chrome, and detail layout styles. The route still has no tabs — Settings stays on its legacy surface behind the modernization filter until a later PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the empty inspector with `<SubscriberDetailContent>` reading `?subscriber=…&u=…` from the URL — boot's router already gates the mount on those params via `route.inspector` (added in #48574). Wraps the slot in its own `QueryClientProvider` so subscriber-detail queries share the cache the stage has already warmed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
397ab60 to
a43e4c7
Compare
…ter + add tests Until the dashboard UI ships, register no /wpcom/v2/subscribers/* routes unless `rsm_jetpack_ui_modernization_newsletter` is on — same gate the wp-build page already uses. The check lives inside `register_routes()` (which fires on `rest_api_init`) so theme- or plugin-added filters are applied before it evaluates, instead of at file-load time when only mu-plugins have run. Adds a focused test class covering the new gate, the cap check (anon and under-privileged users), and the handler-level input validation paths in `add` / `remove` / `individual` / `stats` — the layers most likely to silently regress without coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pass `noopener,noreferrer` to `window.open` for the page-header CSV download — matches the pattern used everywhere else we open a new tab. Adds Jest coverage for `useSubscriberRemoveMutation`: singular vs bulk snackbar copy, the partial-failure path that emits both success and error notices, and the MAX_BULK_REMOVE cap that protects WP.com from a runaway selection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lifting `Gravatar` into `@automattic/jetpack-components` made every package whose tests touch that components index transitively evaluate `gravatar/index.tsx`, which side-effect imports `@gravatar-com/hovercards/dist/style.css`. Jest's default behavior is to skip `node_modules` for transformation, so the CSS reached the JS parser and blew up with `SyntaxError: Unexpected token '.'` across publicize, social, and the plugins/jetpack admin-page tests. Two configs maintain their own allowlists: the shared base config in `tools/js-tools/jest/config.base.js`, and the plugins/jetpack gui runner at `projects/plugins/jetpack/tests/jest.config.gui.js`. The gui runner's local pattern overrides the base via `transformIgnorePatterns` set semantics (union — any matching pattern wins, so a local "ignore" beats a base "unignore"), so both need the same allowlist entry. Adds `@gravatar-com` to both alongside `uplot` and `@wordpress/admin-ui`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
871e74f to
92fca54
Compare
Part of #48530 — third of six PRs to modernize Jetpack's Newsletter into a unified wp-admin product. Builds on the page-shell chassis from #48574 (now on trunk) by filling the empty
<Page>body with the Subscribers DataViews list, the row + bulk action modals, and the subscriber-detail inspector.Proposed changes
<Page title="Newsletter" />with<SubscribersBody>— selection, modal orchestration, and the<SubscribersDataViews>mount — wrapped in the sameQueryClientProviderand page chrome. Adds the page subtitle ("Manage everyone subscribed to your site.") and the Add Subscribers / More options header actions.<SubscriberDetailContent>in the Inspector slot when?subscriber=…&u=…is present. The chassis already wiredroute.inspectorto that boolean; this PR just fills the slot._inc/subscribers/data/*REST client + React Query hooks) and the lib helpers (CSV parse, DataViews i18n, site context, plans, status, Tracks, view-state) directly from Newsletter: unify Subscribers + Settings into a single wp-admin product #48420. The existingquery-client.tsfrom the chassis is the same one referenced everywhere.subscribers-data-views.tsx,subscribers-body.tsx,cells/,detail/,modals/,header-actions.tsx,empty-state.tsx,jetpack-logo.tsx— from Newsletter: unify Subscribers + Settings into a single wp-admin product #48420.Gravatar(with hovercard support, SHA-256 hashing, configurabledefaultImage) from Forms into@automattic/jetpack-components/gravatar. Forms switches to it; the per-package@gravatar-com/hovercardsandjs-sha256deps move with it. Newsletter consumes the lifted version directly.WPCOM_REST_API_V2_Endpoint_Subscribers_Listregistering/wpcom/v2/subscribers/{list,individual,totals,stats,add,remove,products,comp,remove-comp}. Each route proxies to the corresponding WP.com endpoint viaAutomattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user. Glob-loaded — no loader edits. Route registration is gated behind the samersm_jetpack_ui_modernization_newsletterfilter the UI uses, so on flag-off sites the proxy is a no-op (rest_no_route).add/remove/individual/stats) and Jest coverage foruseSubscriberRemoveMutation(singular vs bulk snackbar copy, the partial-failure aggregator, theMAX_BULK_REMOVEcap).All gated behind
rsm_jetpack_ui_modernization_newsletter. With the flag off, the legacy Newsletter Settings page renders unchanged.Related product discussion/links
02e8b93e25(rebrand + Gravatar lift)Does this pull request change what data or activity we track or use?
wpcom/v2/subscribers/{list,individual,totals,stats,add,remove,products,comp,remove-comp}. Each one calls the corresponding WP.com endpoint via the existing site connection — no new identifiers or payloads beyond what WP.com already returns. Mirrors the surface that Newsletter: unify Subscribers + Settings into a single wp-admin product #48420 was about to ship. Routes only register when the modernization filter is on, so flag-off sites expose no new surface.jetpack_newsletter_tab_viewevent from the original umbrella lands in PR 6 along with the rest of the telemetry pass.add_script_datapayload. No new keys.Testing instructions
Pull this branch, run
pnpm installandpnpm jetpack build plugins/jetpack --depsto refresh both Newsletter and the Jetpack plugin's REST surface. Then verify both flag states.Flag OFF (regression check)
add_filter( 'rsm_jetpack_ui_modernization_newsletter', ... )exists in any mu-plugin /wp-config.php/ theme.wp-admin/admin.php?page=jetpack-newsletter.analytics.initializestill fires fromNewsletterSettingsApp(untouched by this PR).curl -s /wp-json/wpcom/v2/subscribers/list -H 'X-WP-Nonce: …'should returnrest_no_route— the proxy is gated off too..jp-forms__gravatarto.jetpack-components-gravatar, but the sameborder-radius: 50%+ flex-shrink rules apply).Flag ON (Subscribers list)
add_filter( 'rsm_jetpack_ui_modernization_newsletter', '__return_true' );to a mu-plugin or Code Snippet.wp-admin/admin.php?page=jetpack-newsletter.?sort=date_subscribed. Reload — sort persists.?subscriber=…&u=…. Click the close button — params strip; inspector disappears.user_id, Comp a subscription offers a plan picker; Remove comp undoes it.build/pages/jetpack-newsletter-dashboard/, not the legacynewsletter.js. No console errors.Toggle round-trip
add_filterline and refresh — legacy Newsletter Settings page returns immediately.Screenshots
Subscribers list (flag on)