You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Builds on #12537 by registering the first PDF-capable widget in the core widget registry: the All Traffic widget on the Traffic dashboard (Traffic → Site traffic over time → All Visitors).
This ticket lands:
A new shared PDFMetricTile primitive used by every metric tile across the PDF report (Core pipeline: Export an MVP PDF #12536 explicitly excludes shared primitives, so this is the first one).
The All Visitors widget's PDF data loader (getPDFData) - returns the two GA4 reports needed for the metric tile and the line chart. Chart capture is intentionally deferred to Create PDF Chart capture utilities #12629; this ticket returns { data } only.
The All Visitors widget's @react-pdf/renderer component (indexPDF) - renders one PDFMetricTile followed by a fixed-size empty placeholder where the line chart will land in Create PDF Chart capture utilities #12629.
The widget registration update wiring Component, getData, and label into the widget's existing registerWidget call.
No user-visible change yet - the orchestrator and sidesheet do not consume the registry's new pdf field until #12631 lands. This ticket is verified by unit tests against the new files; end-to-end behavior is covered by #12631's AC.
Do not alter or remove anything below. The following sections will be managed by moderators only.
Acceptance criteria
The All Traffic widget registration declares a pdf field with Component, getData, and label set. After this ticket lands, select( CORE_WIDGETS ).getWidgets( areaSlug, { pdf: true } ) (using AREA_MAIN_DASHBOARD_TRAFFIC_PRIMARY or the equivalent slug) returns the All Traffic widget; calling getWidgets without pdf: true returns the same widgets it always has.
Calling widget.pdf.getData( { registry, dates, signal } ) resolves with { data: { totalsReport, graphReport } } - the two GA4 reports loaded in parallel via Promise.all. (Chart capture lands in Create PDF Chart capture utilities #12629 and extends this same file.)
getPDFData short-circuits cleanly when signal.aborted flips between awaits.
The All Visitors PDF component renders against shaped fixtures: one "All Visitors" metric tile (total users + period-over-period delta + comparison label) followed by a fixed-size empty placeholder block where the chart will be filled in by Create PDF Chart capture utilities #12629.
The All Visitors PDF component renders a "No data available" placeholder when data is nullish.
The shared PDFMetricTile renders title, value, sub-text, and the optional up/down percentage change badge against shaped fixtures.
The dashboard's All Traffic widget continues to render exactly as before - the new reportOptions.ts is a pure refactor of the existing report arguments and is consumed by both the dashboard hook and the PDF loader so they cannot drift.
View-only filtering on getWidgets( ..., { modules, pdf: true } ) still excludes the widget when Analytics 4 is not shared with the user's role.
Feature remains gated behind the PDF export feature flag (no UI surface changes here - the sidesheet does not consume the registry yet).
Implementation Brief
Files to modify
Frontend - Analytics 4 widget (first PDF slice)
Create file assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/reportOptions.ts - extract the GA4 getReport arguments for the All Visitors totals and the date-dimension graph into a single module. Imported by both hooks/useAllTrafficReports and the new getPDFData.ts so dashboard and PDF cannot drift.
Calls registry.resolveSelect( MODULES_ANALYTICS_4 ).getReport() for both reports in Promise.all.
Bails out early if signal.aborted between awaits.
Returns { data: { totalsReport, graphReport } }. No chartImages in this ticket - chart rasterisation lands in Create PDF Chart capture utilities #12629, which extends this file.
Create file assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/indexPDF.tsx - @react-pdf/renderer component rendering one PDFMetricTile ("All Visitors" + total + period-over-period delta) followed by a fixed-size <View> placeholder (e.g. style={ { width: '100%', height: 200, backgroundColor: '#f5f5f5' } }) that occupies the space the line chart will fill in Create PDF Chart capture utilities #12629. No pie chart, no dimension tabs, no extra sub-headings. Renders a "No data available" placeholder when data is nullish. (.tsx follows the project's "all new frontend work in TypeScript" rule.) Create PDF Chart capture utilities #12629 replaces the placeholder <View> with <Image src={ chartImages.lineChart } /> and adds the chartImages prop type.
Update file assets/js/modules/analytics-4/widgets/index.js - on the existing registerWidget( 'analyticsAllTrafficGA4', { ... } ) call, add pdf: { Component: DashboardAllTrafficWidgetGA4PDF, getData: getPDFData, label: __( 'All Visitors', 'google-site-kit' ) }, importing both from the widget directory above. The label is set now even though All Visitors is the only PDF-capable widget in AREA_MAIN_DASHBOARD_TRAFFIC_PRIMARY - DashboardReport (Drive the PDF orchestrator and side sheet from the widget registry and core/pdf store #12631) suppresses the sub-section heading for single-widget areas anyway, and presetting the label avoids a follow-up edit when the next ticket adds a second PDF widget to this area. No other widget registration is touched.
Frontend - Shared PDF primitive
Create file assets/js/components/PDFExport/components/PDFMetricTile.tsx - shared @react-pdf/renderer tile with title, value, sub-text, and optional up/down percentage change badge. Used by the All Visitors tile in this ticket and reused by every later section ticket. (Core pipeline: Export an MVP PDF #12536 explicitly excludes shared primitives - this is the first one.)
Google Charts CDN loader and the offscreen rasteriser are intentionally out of scope here - they land in follow-up #12629 alongside the All Visitors line chart fill-in. This ticket only renders a sized placeholder where the chart will go, so the registry-and-component pipeline can be validated without depending on the chart capture infrastructure.
Test Coverage
Jest: assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/getPDFData.test.ts - All Traffic loader resolves both reports in parallel, returns the expected { data: { totalsReport, graphReport } } shape, short-circuits when signal.aborted flips between awaits.
Jest: assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/indexPDF.test.tsx - renders cleanly with shaped fixtures; renders the "No data available" placeholder when data is null. (Chart <Image> rendering is covered by Create PDF Chart capture utilities #12629.)
Jest: assets/js/components/PDFExport/components/PDFMetricTile.test.tsx - renders title, value, sub-text, and the up/down percentage change badge in both directions against shaped fixtures.
No Storybook / VRT - @react-pdf/renderer components render to a PDF document, not the DOM, so there is nothing meaningful for Storybook or VRT to capture. PDF visual fidelity is verified via the dedicated PDF-inspection ticket.
QA Brief
Note: it's not yet possible to test the PDF widget, but this work refactors the report queries for the dashboard widget so the following steps can confirm the behaviour is maintained for this widget on the dashboard.
On the main dashboard with Analytics connected and traffic data populated, open the Traffic section and verify the All Visitors widget loads with a total user count, a percentage change badge against the previous period, and a line chart of users over time.
Click between the Channels, Locations, and Devices dimension tabs in the All Visitors widget and verify the pie chart, totals, and line chart update correctly for each selection.
Switch the dashboard date range across all available options and verify the All Visitors widget refreshes for each one.
Open the page-level dashboard for a specific post or page and verify the All Visitors widget shows traffic scoped to that URL.
Sign in as a view-only user without Analytics shared with their role and verify the All Visitors widget is not visible on the dashboard.
Changelog entry
Add PDF Report support for the All Traffic Widget.
Feature Description
Builds on #12537 by registering the first PDF-capable widget in the core widget registry: the All Traffic widget on the Traffic dashboard (Traffic → Site traffic over time → All Visitors).
This ticket lands:
PDFMetricTileprimitive used by every metric tile across the PDF report (Core pipeline: Export an MVP PDF #12536 explicitly excludes shared primitives, so this is the first one).getPDFData) - returns the two GA4 reports needed for the metric tile and the line chart. Chart capture is intentionally deferred to Create PDF Chart capture utilities #12629; this ticket returns{ data }only.@react-pdf/renderercomponent (indexPDF) - renders onePDFMetricTilefollowed by a fixed-size empty placeholder where the line chart will land in Create PDF Chart capture utilities #12629.Component,getData, andlabelinto the widget's existingregisterWidgetcall.No user-visible change yet - the orchestrator and sidesheet do not consume the registry's new
pdffield until #12631 lands. This ticket is verified by unit tests against the new files; end-to-end behavior is covered by #12631's AC.Do not alter or remove anything below. The following sections will be managed by moderators only.
Acceptance criteria
pdffield withComponent,getData, andlabelset. After this ticket lands,select( CORE_WIDGETS ).getWidgets( areaSlug, { pdf: true } )(usingAREA_MAIN_DASHBOARD_TRAFFIC_PRIMARYor the equivalent slug) returns the All Traffic widget; callinggetWidgetswithoutpdf: truereturns the same widgets it always has.widget.pdf.getData( { registry, dates, signal } )resolves with{ data: { totalsReport, graphReport } }- the two GA4 reports loaded in parallel viaPromise.all. (Chart capture lands in Create PDF Chart capture utilities #12629 and extends this same file.)getPDFDatashort-circuits cleanly whensignal.abortedflips between awaits.datais nullish.PDFMetricTilerenders title, value, sub-text, and the optional up/down percentage change badge against shaped fixtures.reportOptions.tsis a pure refactor of the existing report arguments and is consumed by both the dashboard hook and the PDF loader so they cannot drift.getWidgets( ..., { modules, pdf: true } )still excludes the widget when Analytics 4 is not shared with the user's role.Implementation Brief
Files to modify
Frontend - Analytics 4 widget (first PDF slice)
assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/reportOptions.ts- extract the GA4getReportarguments for the All Visitors totals and the date-dimension graph into a single module. Imported by bothhooks/useAllTrafficReportsand the newgetPDFData.tsso dashboard and PDF cannot drift.assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/getPDFData.ts- default-exportsgetPDFData( { registry, dates, signal } )which:reportOptions.tsfor the supplieddates(the orchestrator in Drive the PDF orchestrator and side sheet from the widget registry andcore/pdfstore #12631 passes a date range that excludes the current day per the design doc's Reporting Period rule).registry.resolveSelect( MODULES_ANALYTICS_4 ).getReport()for both reports inPromise.all.signal.abortedbetween awaits.{ data: { totalsReport, graphReport } }. NochartImagesin this ticket - chart rasterisation lands in Create PDF Chart capture utilities #12629, which extends this file.assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/indexPDF.tsx-@react-pdf/renderercomponent rendering onePDFMetricTile("All Visitors" + total + period-over-period delta) followed by a fixed-size<View>placeholder (e.g.style={ { width: '100%', height: 200, backgroundColor: '#f5f5f5' } }) that occupies the space the line chart will fill in Create PDF Chart capture utilities #12629. No pie chart, no dimension tabs, no extra sub-headings. Renders a "No data available" placeholder whendatais nullish. (.tsxfollows the project's "all new frontend work in TypeScript" rule.) Create PDF Chart capture utilities #12629 replaces the placeholder<View>with<Image src={ chartImages.lineChart } />and adds thechartImagesprop type.assets/js/modules/analytics-4/widgets/index.js- on the existingregisterWidget( 'analyticsAllTrafficGA4', { ... } )call, addpdf: { Component: DashboardAllTrafficWidgetGA4PDF, getData: getPDFData, label: __( 'All Visitors', 'google-site-kit' ) }, importing both from the widget directory above. Thelabelis set now even though All Visitors is the only PDF-capable widget inAREA_MAIN_DASHBOARD_TRAFFIC_PRIMARY-DashboardReport(Drive the PDF orchestrator and side sheet from the widget registry andcore/pdfstore #12631) suppresses the sub-section heading for single-widget areas anyway, and presetting the label avoids a follow-up edit when the next ticket adds a second PDF widget to this area. No other widget registration is touched.Frontend - Shared PDF primitive
assets/js/components/PDFExport/components/PDFMetricTile.tsx- shared@react-pdf/renderertile with title, value, sub-text, and optional up/down percentage change badge. Used by the All Visitors tile in this ticket and reused by every later section ticket. (Core pipeline: Export an MVP PDF #12536 explicitly excludes shared primitives - this is the first one.)Test Coverage
assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/getPDFData.test.ts- All Traffic loader resolves both reports in parallel, returns the expected{ data: { totalsReport, graphReport } }shape, short-circuits whensignal.abortedflips between awaits.assets/js/modules/analytics-4/components/dashboard/DashboardAllTrafficWidgetGA4/indexPDF.test.tsx- renders cleanly with shaped fixtures; renders the "No data available" placeholder whendatais null. (Chart<Image>rendering is covered by Create PDF Chart capture utilities #12629.)assets/js/components/PDFExport/components/PDFMetricTile.test.tsx- renders title, value, sub-text, and the up/down percentage change badge in both directions against shaped fixtures.No Storybook / VRT -
@react-pdf/renderercomponents render to a PDF document, not the DOM, so there is nothing meaningful for Storybook or VRT to capture. PDF visual fidelity is verified via the dedicated PDF-inspection ticket.QA Brief
Note: it's not yet possible to test the PDF widget, but this work refactors the report queries for the dashboard widget so the following steps can confirm the behaviour is maintained for this widget on the dashboard.
Changelog entry