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
Build the Traffic > Search traffic over time PDF widget. The dashboard's SearchFunnelWidgetGA4 shows the same four metrics behind a tab switcher: Total impressions and Total clicks from Search Console, Unique visitors from Search and Key events from Analytics 4 (both filtered to the Organic Search channel). The PDF flattens this into a 2x2 grid where all four metric + line chart tiles are visible at once, each with its total, period-over-period delta chip, and a current vs previous period dotted-line overlay, per the Figma design.
This ticket introduces a new shared @react-pdf/renderer primitive, PDFMetricChartTile, that combines a metric tile (title, large value, delta chip) with a line chart image and a current/previous legend. The Search Funnel widget is the first consumer; later tickets that need the same "headline number with a comparison time series" tile (e.g. Content > Top content over time, Monetization > Earning performance over time) will reuse it. The widget reuses #12629's chart capture helpers (ensureGoogleChartsLoaded + renderGoogleChartToDataURI) for the four line charts, threads the orchestrator's signal through every fetch via the per-store opt-in landing in #12699, and registers its pdf configuration on the existing searchFunnelGA4 widget per the registry contract from #12537.
Do not alter or remove anything below. The following sections will be managed by moderators only.
Acceptance criteria
A new Search traffic over time tile appears in the Traffic section of the PDF, rendered as a 2x2 grid of four metric + line chart cards: Total impressions, Total clicks, Unique visitors from Search, and Key events.
Each card shows the headline total, a period-over-period delta chip (green for positive, red for negative, with up/down arrow), the "Vs. prev. 28 days" sub-text relative to whichever date range the user has selected, and a smoothed line chart of the metric over the selected date range with a dotted overlay for the previous period.
The chart's current-period line, previous-period dotted line, legend swatches, axis labels, and gridlines visually match the dashboard's Search Funnel widget for the same metric and date range, within JPEG rasterisation fidelity.
Each metric uses the same data source as the dashboard's Search Funnel widget: Total impressions and Total clicks come from Search Console, and Unique visitors and Key events come from Analytics 4 with the sessionDefaultChannelGrouping filtered to Organic Search.
The dashboard's existing Search Funnel widget renders identically to develop for admin, view-only, and entity dashboards after the report option refactor that this ticket performs.
View-only users see the Search traffic over time tile only when both Search Console and Analytics 4 are shared with their role; if either module is unshared or unconnected, the tile is omitted from the PDF and the rest of the Traffic section still renders.
Cancelling during loading aborts before any of the four line charts are rasterised, and no PDF downloads.
If a single metric's report or chart capture fails, that one card renders a "Data unavailable" placeholder while the other three cards and the rest of the PDF still download.
Feature gated behind the pdfGeneration feature flag.
Implementation Brief
Files to modify
Frontend - shared PDF metric + chart primitive
Create file assets/js/components/pdf-export/shared-react-pdf-components/PDFMetricChartTile.tsx - shared @react-pdf/renderer card that stacks a PDFMetricTile (from Register the first PDF widget via the registry: Traffic → All Visitors (excluding chart generation) #12630) over a line chart <Image> with a two-series legend ("Current period" + "Previous period"). Accepts a title, large value, sub-text, delta + direction, current/previous series labels, and a chartImage JPEG data URI. Renders a "Data unavailable" placeholder when chartImage is nullish. Layout uses the existing card background tokens from pdf-theme.ts.
Frontend - Search Funnel widget (PDF slice)
Create file assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/reportOptions.ts - extract the four existing report argument shapes from index.js (Search Console date series, GA4 key events overview + date series, GA4 unique visitors overview + date series) into shared option builders, each taking dates and returning the args used by fetchGetReport.
Create file assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/getPDFData.ts - default-exports getPDFData( { registry, dates, signal } ) which dispatches fetchGetReport( args, { signal } ) on MODULES_SEARCH_CONSOLE and MODULES_ANALYTICS_4 in parallel for the four metrics, computes each metric's total + period-over-period delta from the returned rows, rasterises four line charts via renderGoogleChartToDataURI (chart type 'LineChart', smoothed curves, dotted second series for the previous period, colours matching the dashboard per metric), and returns { data: { metrics: { impressions, clicks, uniqueVisitors, keyEvents } }, chartImages: { impressions, clicks, uniqueVisitors, keyEvents } }. Bails out early when signal.aborted between awaits. Per-metric report or rasterisation failures are caught and recorded so the component can render a per-card "Data unavailable" placeholder; only when all four fail does the loader throw so the orchestrator transitions the whole widget to its "Data unavailable" fallback.
Create file assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/indexPDF.tsx - @react-pdf/renderer component that arranges four <PDFMetricChartTile> in a 2-column flex wrap matching Figma. The widget renders its own sub-section heading via PDFSubSection ("Search traffic over time") because it shares the Traffic area with the All Visitors widget. Renders a per-card "Data unavailable" placeholder when an individual chartImages.* key is null.
Update file assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/index.js - import the four report option builders from reportOptions.ts rather than inlining the args.
Update file assets/js/modules/search-console/widgets/index.js - on the existing registerWidget( 'searchFunnelGA4', { ... } ) call, add pdf: { Component: SearchFunnelWidgetGA4PDF, getData: getPDFData, label: __( 'Search traffic over time', 'google-site-kit' ) }.
Test Coverage
Jest: assets/js/components/pdf-export/shared-react-pdf-components/PDFMetricChartTile.test.tsx - renders title, value, sub-text, delta chip in both directions (positive green, negative red), current/previous legend swatches, and the chart <Image> against shaped fixtures; renders the "Data unavailable" placeholder when chartImage is null.
Jest: assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/getPDFData.test.ts - asserts the four reports fetch in parallel with signal threaded through each fetchGetReport call; totals and period-over-period deltas are computed correctly from the returned rows; four line charts are rasterised via renderGoogleChartToDataURI with the expected chart options (smoothed, dotted previous series); per-metric failures isolate to that card and do not abort the others; the loader throws only when all four metrics fail; signal.aborted short-circuits between awaits.
Jest: assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/indexPDF.test.tsx - renders four <PDFMetricChartTile> in a 2x2 grid with the expected props derived from data + chartImages; renders a per-card "Data unavailable" placeholder when an individual chartImages.* key is null.
Jest: assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/index.test.tsx (extend the existing suite) - dashboard regression coverage: the existing widget renders the same chart values and tab behaviour after the reportOptions.ts extraction as it did before.
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. Visual fidelity is verified via the dedicated PDF-inspection ticket.
QA Brief
Enabled the pdfGeneration feature flag.
Go to the dashboard and generate the pdf report.
Ensure that you see the Search traffic over time option in the pdf generation panel.
Ensure that the Search traffic over time widget is added to the pdf report and it contains 4 charts.
Basically, it should replicate the main Search traffic over time widget including not showing Analytics charts if the Analytics module is not enabled.
Changelog entry
Add support for "Search traffic over time" in PDF reports.
Feature Description
Build the Traffic > Search traffic over time PDF widget. The dashboard's
SearchFunnelWidgetGA4shows the same four metrics behind a tab switcher: Total impressions and Total clicks from Search Console, Unique visitors from Search and Key events from Analytics 4 (both filtered to the Organic Search channel). The PDF flattens this into a 2x2 grid where all four metric + line chart tiles are visible at once, each with its total, period-over-period delta chip, and a current vs previous period dotted-line overlay, per the Figma design.This ticket introduces a new shared
@react-pdf/rendererprimitive,PDFMetricChartTile, that combines a metric tile (title, large value, delta chip) with a line chart image and a current/previous legend. The Search Funnel widget is the first consumer; later tickets that need the same "headline number with a comparison time series" tile (e.g. Content > Top content over time, Monetization > Earning performance over time) will reuse it. The widget reuses #12629's chart capture helpers (ensureGoogleChartsLoaded+renderGoogleChartToDataURI) for the four line charts, threads the orchestrator's signal through every fetch via the per-store opt-in landing in #12699, and registers itspdfconfiguration on the existingsearchFunnelGA4widget per the registry contract from #12537.Do not alter or remove anything below. The following sections will be managed by moderators only.
Acceptance criteria
sessionDefaultChannelGroupingfiltered to Organic Search.developfor admin, view-only, and entity dashboards after the report option refactor that this ticket performs.pdfGenerationfeature flag.Implementation Brief
Files to modify
Frontend - shared PDF metric + chart primitive
assets/js/components/pdf-export/shared-react-pdf-components/PDFMetricChartTile.tsx- shared@react-pdf/renderercard that stacks aPDFMetricTile(from Register the first PDF widget via the registry: Traffic → All Visitors (excluding chart generation) #12630) over a line chart<Image>with a two-series legend ("Current period" + "Previous period"). Accepts a title, large value, sub-text, delta + direction, current/previous series labels, and achartImageJPEG data URI. Renders a "Data unavailable" placeholder whenchartImageis nullish. Layout uses the existing card background tokens frompdf-theme.ts.Frontend - Search Funnel widget (PDF slice)
assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/reportOptions.ts- extract the four existing report argument shapes fromindex.js(Search Console date series, GA4 key events overview + date series, GA4 unique visitors overview + date series) into shared option builders, each takingdatesand returning the args used byfetchGetReport.assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/getPDFData.ts- default-exportsgetPDFData( { registry, dates, signal } )which dispatchesfetchGetReport( args, { signal } )onMODULES_SEARCH_CONSOLEandMODULES_ANALYTICS_4in parallel for the four metrics, computes each metric's total + period-over-period delta from the returned rows, rasterises four line charts viarenderGoogleChartToDataURI(chart type'LineChart', smoothed curves, dotted second series for the previous period, colours matching the dashboard per metric), and returns{ data: { metrics: { impressions, clicks, uniqueVisitors, keyEvents } }, chartImages: { impressions, clicks, uniqueVisitors, keyEvents } }. Bails out early whensignal.abortedbetween awaits. Per-metric report or rasterisation failures are caught and recorded so the component can render a per-card "Data unavailable" placeholder; only when all four fail does the loader throw so the orchestrator transitions the whole widget to its "Data unavailable" fallback.assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/indexPDF.tsx-@react-pdf/renderercomponent that arranges four<PDFMetricChartTile>in a 2-column flex wrap matching Figma. The widget renders its own sub-section heading viaPDFSubSection("Search traffic over time") because it shares the Traffic area with the All Visitors widget. Renders a per-card "Data unavailable" placeholder when an individualchartImages.*key is null.assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/index.js- import the four report option builders fromreportOptions.tsrather than inlining the args.assets/js/modules/search-console/widgets/index.js- on the existingregisterWidget( 'searchFunnelGA4', { ... } )call, addpdf: { Component: SearchFunnelWidgetGA4PDF, getData: getPDFData, label: __( 'Search traffic over time', 'google-site-kit' ) }.Test Coverage
assets/js/components/pdf-export/shared-react-pdf-components/PDFMetricChartTile.test.tsx- renders title, value, sub-text, delta chip in both directions (positive green, negative red), current/previous legend swatches, and the chart<Image>against shaped fixtures; renders the "Data unavailable" placeholder whenchartImageis null.assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/getPDFData.test.ts- asserts the four reports fetch in parallel withsignalthreaded through eachfetchGetReportcall; totals and period-over-period deltas are computed correctly from the returned rows; four line charts are rasterised viarenderGoogleChartToDataURIwith the expected chart options (smoothed, dotted previous series); per-metric failures isolate to that card and do not abort the others; the loader throws only when all four metrics fail;signal.abortedshort-circuits between awaits.assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/indexPDF.test.tsx- renders four<PDFMetricChartTile>in a 2x2 grid with the expected props derived fromdata+chartImages; renders a per-card "Data unavailable" placeholder when an individualchartImages.*key is null.assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/index.test.tsx(extend the existing suite) - dashboard regression coverage: the existing widget renders the same chart values and tab behaviour after thereportOptions.tsextraction as it did before.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. Visual fidelity is verified via the dedicated PDF-inspection ticket.QA Brief
pdfGenerationfeature flag.Search traffic over timeoption in the pdf generation panel.Search traffic over timewidget is added to the pdf report and it contains 4 charts.Search traffic over timewidget including not showing Analytics charts if the Analytics module is not enabled.Changelog entry