WP Manifestindependent plugin directory
manifest / content / bdc-print-pdf

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

0stars
0forks

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.zip

Ships 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_content ACF field, if present.
    • The page_builder ACF Flexible Content field — only insights_content_module rows are included, and only rows with content_type of content-text, content-quote, content-table, or content-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 the wp_ninja_table_items DB table where possible, falling back to do_shortcode() output.
  • 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.css in 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) on template_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

  1. Activate the plugin.
  2. Add [bdc_print_pdf] to a template or the page builder where you want the download button to appear.
  3. 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:

  1. Bump the Version: header and the BDC_PP_VERSION constant in bdc-print-pdf.php, and add a CHANGELOG.md entry.
  2. Commit and push to main.
  3. 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.