Skip to content

Implement PDF Widgets for "Traffic" -> "Search traffic over time" #12545

Description

@benbowler

Feature Description

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.

Image

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Medium priorityTeam SIssues for Squad 1Type: EnhancementImprovement of an existing feature

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions