Skip to content

Read Offline Hooks Reference

Comprehensive list of filters and actions exposed by the Read Offline plugin (version 0.2.4).

Each entry shows: Purpose • Arguments • Expected return (for filters) • Example usage.


Modify which export format slugs are exposed in the frontend UI (after user settings).

Args: (array $formats) Return: array filtered list (subset of ['pdf','epub','md'])

add_filter( 'read_offline_enabled_formats', function( $formats ) {
// Hide EPUB site‑wide, for example.
return array_diff( $formats, [ 'epub' ] );
} );

Last chance to adjust the post HTML before conversion per format.

Args: (string $html, WP_Post $post, string $format) Return: string

add_filter( 'read_offline_content_html', function( $html, $post, $format ) {
if ( 'pdf' === $format ) {
$html .= '<p><em>Downloaded on ' . esc_html( date( 'c' ) ) . '</em></p>';
}
return $html;
}, 10, 3 );

Provide fully generated Markdown yourself (short‑circuit). Return non-null to skip internal conversion.

Args: (null|string $override, string $title, string $originalHtml, array $args) Return: string|null

Tweak final Markdown after internal conversion.

Args: (string $markdown, string $title, string $originalHtml, array $args) Return: string

add_filter( 'read_offline_markdown_post', function( $md ) {
return $md . "\n\n---\nGenerated by MySite";
} );

Alter the computed EPUB CSS (profile + custom CSS amalgam).

Args: (string $css, WP_Post|null $post, array $epub_opts) Return: string

Modify the inline EPUB TOC <ul>…</ul> before insertion.

Args: (string $tocHtml, WP_Post|null $post, int $depth) Return: string

add_filter( 'read_offline_epub_toc_html', fn( $toc ) => '<nav class="toc">' . $toc . '</nav>' );

Supply a custom cover before plugin resolves featured/logo/custom.

Args: (null|array $current, WP_Post|null $post, array $epub_opts) Return: null|array [$filename, $binaryBytes, $mime]

add_filter( 'read_offline_epub_cover', function( $cover, $post ) {
if ( $cover || ! $post ) return $cover;
$custom_path = WP_CONTENT_DIR . '/uploads/branding/epub-cover.jpg';
if ( file_exists( $custom_path ) ) {
return [ 'brand-cover.jpg', file_get_contents( $custom_path ), 'image/jpeg' ];
}
return $cover;
}, 10, 2 );

Append or override PDF CSS (returned string concatenated after base rules + custom setting).

Args: (string $appendCss, WP_Post|null $post) Return: string

add_filter( 'read_offline_pdf_css', function( $extra ) {
return $extra . ' h2{color:#336699;} '; // simple tint
} );

Modify manual PDF TOC <ul> (used ONLY when page numbers are disabled; with page numbers mPDF builds its own TOC from bookmarks).

Args: (string $tocHtml, WP_Post|null $post, int $depth) Return: string

Change the heading text (default “Contents”) for both PDF & EPUB TOCs.

Args: (string $defaultTitle, string $format) Return: string

add_filter( 'read_offline_toc_title', function( $title, $format ) {
return ( 'pdf' === $format ) ? __( 'Document Overview', 'mytheme' ) : $title;
}, 10, 2 );

See read_offline_epub_cover above.

Control whether a bulk export should combine into one file.

Args: (bool $combine, array $post_ids, string $format, string $post_type) Return: bool

add_filter( 'read_offline_bulk_combine', function( $combine, $post_ids, $format ) {
if ( 'pdf' === $format && count( $post_ids ) > 25 ) {
// Force ZIP for very large selections.
return false;
}
return $combine;
}, 10, 3 );

Modify the ZIP filename (string) prior to creating a bulk archive (when not combining).

Args: (string $zip_name, array $generated, string $format, string $post_type) Return: string

add_filter( 'read_offline_bulk_zip_name', function( $name, $generated, $format ) {
return 'my-site-' . $format . '-' . date( 'Ymd-His' ) . '.zip';
}, 10, 3 );

Adjust the temporary auxiliary DB/storage directory path if used.

Args: (string $defaultPath) Return: string

add_filter( 'read_offline_db_path', fn( $p ) => WP_CONTENT_DIR . '/cache/read-offline-db/' );

Fires after an internal auxiliary DB directory is removed.

Args: (string $path, bool $success)

add_action( 'read_offline_db_deleted', function( $path, $ok ) {
error_log( 'Read Offline cache dir deleted: ' . $path . ' (success=' . ( $ok ? '1' : '0' ) . ')' );
} );

Runs immediately after a single EPUB has been written (before optional validation filter outcome is enforced). Use to trigger async validation processes or logging.

Args: (string $path, WP_Post $post, array $epub_opts)

add_action( 'read_offline_epub_generated', function( $path, $post ) {
error_log( 'EPUB created: ' . $path );
}, 10, 2 );

Cloudflare Browser Rendering Filters & Actions

Section titled “Cloudflare Browser Rendering Filters & Actions”

Filter whether to use Cloudflare Browser Rendering for single PDF generation. Defaults to true if Cloudflare credentials are configured.

Args: (bool $use_cloudflare, WP_Post $post, array $pdf_opts, array $gen_opts) Return: bool

add_filter( 'read_offline_use_cloudflare', function( $use, $post, $pdf_opts, $gen_opts ) {
// Always use mPDF for specific post types.
if ( 'product' === $post->post_type ) {
return false;
}
return $use;
}, 10, 4 );

Filter whether to use Cloudflare Browser Rendering for combined PDF generation. Defaults to true if Cloudflare credentials are configured.

Args: (bool $use_cloudflare, array $post_ids, array $pdf_opts, array $gen_opts) Return: bool

add_filter( 'read_offline_use_cloudflare_combined', function( $use, $post_ids, $pdf_opts, $gen_opts ) {
// Use Cloudflare only for large exports (10+ posts).
return count( $post_ids ) >= 10;
}, 10, 4 );

Triggered when Cloudflare PDF generation fails. Return true to fallback to mPDF, false to propagate error.

Args: (bool $fallback, WP_Error $error, WP_Post|null $post) Return: bool

add_filter( 'read_offline_cloudflare_fallback', function( $fallback, $error, $post ) {
// Never fallback for premium content.
if ( $post && has_term( 'premium', 'category', $post ) ) {
return false; // Force Cloudflare, propagate error if it fails.
}
return $fallback; // Default behavior.
}, 10, 3 );

Filter Cloudflare PDF options before building Puppeteer script. Allows customization of format, margins, headers, footers, etc.

Args: (array $options, WP_Post|null $post) Return: array

add_filter( 'read_offline_cloudflare_pdf_options', function( $options, $post ) {
// Force landscape for specific posts.
if ( $post && has_tag( 'wide-content', $post ) ) {
$options['landscape'] = true;
}
return $options;
}, 10, 2 );

Filter the raw Puppeteer JavaScript sent to Cloudflare Browser Rendering API.

Args: (string $script, array $options, WP_Post|null $post) Return: string

add_filter( 'read_offline_cloudflare_puppeteer_script', function( $script, $options, $post ) {
// Add custom JavaScript before PDF generation.
$custom = "await page.evaluate(() => { console.log('Generating PDF...'); });";
return str_replace( 'await page.pdf(', $custom . "\n await page.pdf(", $script );
}, 10, 3 );

Filter the complete HTML document before sending to Cloudflare for PDF rendering.

Args: (string $full_html, WP_Post|null $post, array $pdf_opts, array $gen_opts) Return: string

add_filter( 'read_offline_cloudflare_html', function( $html, $post, $pdf_opts, $gen_opts ) {
// Inject custom analytics or tracking scripts.
$tracking = '<script>console.log("PDF generated via Cloudflare");</script>';
return str_replace( '</body>', $tracking . '</body>', $html );
}, 10, 4 );

Filter the combined HTML document for multi-post PDFs before sending to Cloudflare.

Args: (string $full_html, array $post_ids, array $pdf_opts, array $gen_opts) Return: string

add_filter( 'read_offline_cloudflare_combined_html', function( $html, $post_ids, $pdf_opts, $gen_opts ) {
// Add cover page for combined exports.
$cover = '<div style="page-break-after:always;"><h1>Combined Export</h1><p>' . count( $post_ids ) . ' posts</p></div>';
return str_replace( '<div class="combined-content">', $cover . '<div class="combined-content">', $html );
}, 10, 4 );

Filter the HTTP timeout for Cloudflare API requests (default: 60 seconds).

Args: (int $timeout) Return: int

add_filter( 'read_offline_cloudflare_timeout', function( $timeout ) {
// Increase timeout for large documents.
return 120; // 2 minutes
} );

Action fired after successful Cloudflare PDF generation.

Args: (string $path, WP_Post|null $post, array $response)

add_action( 'read_offline_cloudflare_pdf_generated', function( $path, $post, $response ) {
// Log successful generation.
error_log( sprintf( 'Cloudflare PDF generated: %s (Post ID: %d)', basename( $path ), $post ? $post->ID : 0 ) );
}, 10, 3 );

Action fired when Cloudflare PDF generation fails.

Args: (WP_Error $error, WP_Post|null $post, string $html)

add_action( 'read_offline_cloudflare_pdf_failed', function( $error, $post, $html ) {
// Alert admins of Cloudflare failures.
$admin_email = get_option( 'admin_email' );
wp_mail(
$admin_email,
'Cloudflare PDF Generation Failed',
sprintf( 'Error: %s\nPost ID: %d', $error->get_error_message(), $post ? $post->ID : 0 )
);
}, 10, 3 );

Allows you to validate or veto a generated EPUB file. Return WP_Error to signal a failure (the file stays on disk; caller will receive the error).

Args: (mixed $ok, string $path, WP_Post $post, array $epub_opts) Return: bool|WP_Error (true to accept, WP_Error to reject)

Example integrating epubcheck (Java) if installed server-side:

add_filter( 'read_offline_epub_validate', function( $ok, $path ) {
if ( is_wp_error( $ok ) ) { return $ok; }
$jar = '/usr/local/bin/epubcheck.jar';
if ( ! file_exists( $jar ) ) { return $ok; }
$cmd = escapeshellcmd( 'java -jar ' . $jar . ' ' . escapeshellarg( $path ) . ' 2>&1' );
@exec( $cmd, $out, $code );
if ( $code !== 0 ) {
return new WP_Error( 'epub_invalid', 'EPUB failed validation', array( 'output' => $out ) );
}
return $ok; // pass through
}, 10, 2 );

For ZIP and combined downloads the plugin now sends: Content-Length, X-Checksum-MD5, X-Checksum-SHA256 allowing clients to verify integrity.


  • Read_Offline_Export::invalidate_post_cache( $post_id, $format = null ) – Remove cached exports so they regenerate.
  • Read_Offline_Export::debug_smoke_capabilities() – Returns array of environment availability (mPDF / PHPePub).
  • Standard WordPress hooks like the_content still apply before plugin filters.
  • When PDF page numbers are enabled, mPDF’s own TOC replaces the manual TOC filter (read_offline_pdf_toc_html not invoked in that case).

Suggestions or missing hook docs? Open an issue / submit a PR.