Tracking issue: #1539 Release: Chart Builder
3.6.0· PRC Platform1.5Work period: March 2026 Scope:prc-chart-builder
Overview
Chart Builder 3.6.0 is a focused patch release that ships the server-side PNG export service end-to-end. Charts can now be automatically screenshotted via ScreenshotOne, stored as WordPress media attachments, and served as a static fallback image on the frontend. The release also fixes rendering and layout issues in the chart viewer toolbar and for synced (ref) charts.
What's New
1. Server-Side PNG Export Service (Issue #1539)
Charts can now be exported to PNG entirely on the server, with no client-side dependency.
How it works:
- When a chart post is saved or a WP-CLI backfill is triggered, an Action Scheduler job is queued for that post.
- The job calls
PNG_Export::generate_png(), which builds the chart's public URL, calls the ScreenshotOne API with the chart's pixel dimensions, and receives a binary PNG. - The PNG is sideloaded into the WordPress media library, attached to the chart post and set as its featured image.
- The attachment ID, public URL, and a hash of the current chart attributes are written to post meta (
_chart_png_attachment_id,_chart_png_url,_chart_attributes_hash). The hash is used on subsequent saves to skip regeneration when nothing has changed. - Old attachments are deleted automatically when a new PNG is generated.
CLI backfill:
# Dry run (default) — shows what would be processed
wp prc chart-builder backfill_pngs
# Execute against production
wp prc chart-builder backfill_pngs --dry-run=false
# Target a specific multisite URL
wp prc chart-builder backfill_pngs --dry-run=false --url=alpha.pewresearch.org/pewresearch-org
# Use a remote export URL for local testing
wp prc chart-builder backfill_pngs --dry-run=false --export-url=https://alpha.pewresearch.org/pewresearch-org
Relevant constants (set in vip-config/keys-and-tokens.php):
PRC_PLATFORM_SCREENSHOTONE_ACCESS_KEYPRC_PLATFORM_SCREENSHOTONE_SECRET_KEY
2. Static Fallback Image on the Frontend
The chart block now renders a proper fallback when a PNG is available and JavaScript has not yet hydrated (or is unavailable).
- PNG available — renders
<img class="chart-fallback chart-fallback--png">sized to the chart's configured layout width. - PNG not yet generated — renders
<div class="chart-fallback chart-fallback--placeholder">with a light-gray background and the chart's configured minimum height (or 200px).
When the PNG fallback is displayed, duplicate metadata (title, subtitle, note, tag, divider) is hidden via a CSS :has() rule so they aren't shown twice alongside the image.
3. Synced Chart (refId) Support
Synced chart instances — where a chart block references another chart post via refId — now correctly resolve PNG meta from the source chart post rather than the post they are embedded in.
- The controller block passes
refIdas block context when rendering the inner chart block server-side. class-chart.phpuses$block->context['refId'] ?? get_the_ID()when looking up_chart_png_url, so the fallback image and Download button always point to the canonical chart.- The controller's Download button similarly uses
$chart_ref_id(the resolvedrefId) when reading featured image / PNG URL meta.
Changed
- Viewer toolbar layout — Chart/Data tabs are grouped on the left; Download image and Share are grouped on the right using
flex+space-between. The Download image button is conditionally shown only when a PNG URL exists. - Active tab display —
.wp-chart-builder-chart.activeand.wp-chart-builder-table.activechanged fromdisplay: inline-blocktodisplay: block, removing the phantom line-box gap that appeared above the toolbar. - Figure margin —
figure.wp-chart-builder { margin: 0; }added to strip the browser default figure margin. - Subtitle / note spacing —
margin-bottomon.cb__subtitleandmargin-topon.cb__notereduced to4px.
Fixed
- WP-CLI
backfill_pngsprocessed 0 charts — The subcommand uses an underscore (backfill_pngs), not a hyphen; multisite targeting requires--url=<site-url>. - Export URL built from local permalink on alpha —
generate_png()now accepts an optional$base_urland$export_url_override; the CLI passes--export-urlthrough correctly so ScreenshotOne always hits the intended environment. $export_urloverwritten in CLI loop — Renamed the per-iteration display variable to$display_export_urlso the caller-supplied--export-urloverride is preserved across all iterations.
Security / Logging
- Removed the temporary
do_action( 'qm/debug', ... )alpha-testing block fromgenerate_png(). - Removed the success
error_logcall that fired on every PNG generation. Failure-path error logs are retained for Action Scheduler job debugging.