BDC Print PDF (ACF Page Builder) self-updates
A WordPress plugin that adds a [bdc_print_pdf] shortcode rendering a "Download PDF" button. Clicking it streams a simplified, one-column PDF of the current post, built from ACF Insight fields and a filtered subset of the page_builder flexible content.
by The Bonsai Digital Collective · github.com/bonsai-systems/bdc-print-pdf · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/bonsai-systems/bdc-print-pdf/archive/refs/heads/main.zipShips its own WordPress updater (Plugin Update Checker), so new versions show up under Dashboard → Updates.
Bonsai Print PDF (ACF Page Builder)
A WordPress plugin that adds a [bdc_print_pdf] shortcode rendering a "Download PDF" button. Clicking it streams a simplified, one-column PDF of the current post, built from ACF Insight fields and a filtered subset of the page_builder flexible content.
Features
[bdc_print_pdf label="Download PDF" class="bdc-print-pdf-button"]shortcode — only renders on singular posts of an eligible post type (see "Eligible post types" below).- PDF generation via the bundled Dompdf library (no Composer dependency at runtime — the
dompdf/folder is vendored directly). - Content pulled from:
- Top-level ACF fields:
insight_headline,insight_introduction,associated_authors(relationship field) — rendered as a header with title, intro, author photos and byline. legacy_contentACF field, if present.- The
page_builderACF Flexible Content field — onlyinsights_content_modulerows are included, and only rows withcontent_typeofcontent-text,content-quote,content-table, orcontent-type-table. Video, image, and two-image blocks are intentionally skipped to keep the PDF compact. - Ninja Tables shortcodes (
[ninja_tables id="..."]) found in text or table blocks are expanded to static HTML tables — read directly from thewp_ninja_table_itemsDB table where possible, falling back todo_shortcode()output.
- Top-level ACF fields:
- Footer added to every PDF page via the Dompdf canvas: a clickable "Read the full insight" link (bottom-left) and
page_num / page_count(bottom-right). - First-page logo pulled from the ACF Options field
site_main_logo. - Looks for a dedicated print stylesheet at
assets/css/core/print-pdf.cssin the active child theme first, then the parent theme, and loads it via<link>if found. - Request handling is via a custom query var (
bdc_print_pdf=1) ontemplate_redirect. The URL is stable per post (no nonce, no expiry) — see "PDF endpoint behaviour" below.
Eligible post types
The PDF endpoint only serves singular posts of an allowed post type, filterable via bdc_print_pdf_post_types (default: array( 'post' )):
add_filter( 'bdc_print_pdf_post_types', function ( $types ) {
return array( 'post', 'insights' );
} );
Requests against any other post type (or content that doesn't resolve to a valid post) return 404. This plugin ships to multiple Bonsai sites via the same GitHub release, so this is a filter rather than a hard-coded post type — confirm the correct value for each site before relying on the default.
PDF endpoint behaviour
As of 3.1.0, the endpoint no longer uses a nonce. It previously did (bdc_print_pdf_{$post_id}, verified in template_redirect), but since the endpoint only ever renders a published, publicly-viewable post, there was no state-changing action for the nonce to protect, and it rotated the URL every 12–24 hours. That made the URL uncacheable and, once an expired-nonce URL got indexed, caused it to 500 indefinitely (a bare wp_die() defaults to HTTP 500) — Google recrawls a 500 forever on the assumption it's transient, which on the Dixcart site alone produced ~6,200 indexed, permanently-broken PDF URLs.
Current behaviour:
| Request | Response |
|---|---|
?bdc_print_pdf=1 on an eligible post |
200, application/pdf, Cache-Control: public, max-age=… (filterable via bdc_print_pdf_cache_seconds, default 1 hour), X-Robots-Tag: noindex, nofollow |
?bdc_print_pdf=1&bdc_pp_nonce=<anything> |
410 Gone — legacy nonce URLs are permanently retired, regardless of whether the nonce value would still verify |
?bdc_print_pdf=1 on a non-eligible post type, or an invalid post |
404 |
| Dompdf library missing | 404, with the underlying cause logged via error_log() |
No code path returns a 5xx. Every response — success or failure — carries X-Robots-Tag: noindex, nofollow, since the PDF duplicates the article it's generated from and shouldn't compete with it in search.
Requirements
- WordPress 6.0+
- PHP 8.0+
- ACF (Advanced Custom Fields / ACF Pro) — the plugin degrades gracefully to raw post content if ACF is not active, but the Insight-specific header/fields require it.
- The
dompdf/folder must be present inside the plugin directory (already vendored in this repo).
Usage
- Activate the plugin.
- Add
[bdc_print_pdf]to a template or the page builder where you want the download button to appear. - Optional shortcode attributes:
label— button text (default:Download PDF)class— CSS class on the<a>tag (default:bdc-print-pdf-button)
Data / Fields Used
No custom options are stored by this plugin — it only reads existing ACF field data at request time:
| Field | Type | Used for |
|---|---|---|
insight_headline |
Text | PDF header title (falls back to post title) |
insight_introduction |
Textarea | PDF header intro |
associated_authors |
Relationship | Author photos + byline links |
legacy_content |
WYSIWYG | Optional legacy content block |
page_builder |
Flexible Content | Filtered insights_content_module rows |
site_main_logo |
Image (Options page) | First-page logo |
Security Note
Field values (insight_headline, insight_introduction, legacy_content, module text/quote/table content) are output largely as-authored (via wp_kses_post() or, for the headline/intro, directly) so that editor-authored HTML formatting survives into the PDF. Access to author these fields is restricted to users who can edit the relevant post type — there is no public-facing input on this plugin. The PDF endpoint itself is read-only (it renders an already-public post) and unauthenticated by design; see "PDF endpoint behaviour" above for why it has no nonce.
Updates
Ships with YahnisElsts/plugin-update-checker (installed via Composer, vendor/ committed) pointed at github.com/Bonsai-Systems/bdc-print-pdf. Sites with the plugin installed will see updates in Plugins in wp-admin, same as bonsai-code-injector and bonsai-maintenance.
To ship a new version:
- Bump the
Version:header and theBDC_PP_VERSIONconstant inbdc-print-pdf.php, and add aCHANGELOG.mdentry. - Commit and push to
main. - Publish a GitHub Release tagged with the new version (release-assets mode is enabled, so attach a zip of the plugin folder — plain source-archive tags won't be picked up).
Sites check for updates every 6 hours ($checkPeriod argument to buildUpdateChecker()), or immediately if an admin clicks "Check again" on the Plugins screen.