Implementing automated compliance reporting for custom custom subscription logs ledgers using mpdf engine
// includes/class-csr-reporting.php
namespace Antigravity\CSR;
use Mpdf\Mpdf;
use WP_Query;
class CSR_Reporting {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Reporting();
}
return self::$instance;
}
private function __construct() {
// Hook into WordPress actions/filters if needed
// For example, to trigger report generation via an AJAX call or a cron job
}
/**
* Fetches subscription ledger data for a given date range.
*
* @param string $start_date Start date in YYYY-MM-DD format.
* @param string $end_date End date in YYYY-MM-DD format.
* @return array Array of ledger entries.
*/
public function get_ledger_data( $start_date, $end_date ) {
global $wpdb;
$table_name = $wpdb->prefix . 'subscription_ledger';
$sql = $wpdb->prepare(
"SELECT * FROM {$table_name}
WHERE DATE(timestamp) BETWEEN %s AND %s
ORDER BY timestamp ASC",
$start_date,
$end_date
);
$results = $wpdb->get_results( $sql, ARRAY_A );
return $results;
}
/**
* Generates a PDF report using mPDF.
*
* @param array $data Ledger data to include in the report.
* @param string $report_title Title for the report.
* @return string Path to the generated PDF file.
*/
public function generate_pdf_report( $data, $report_title = 'Subscription Ledger Report' ) {
try {
$mpdf = new Mpdf( [
'mode' => 'utf-8',
'format' => 'A4',
'margin_left' => 15,
'margin_right' => 15,
'margin_top' => 16,
'margin_bottom' => 16,
'margin_header' => 9,
'margin_footer' => 9,
'default_font_size' => 10,
'default_font' => 'dejavusans', // Ensure this font is available or install it
] );
// Set document metadata
$mpdf->SetTitle( $report_title );
$mpdf->SetAuthor( 'Your Company Name' );
$mpdf->SetCreator( 'Custom Subscription Reporter Plugin' );
// Add header and footer
$mpdf->SetHTMLHeader( '<div style="text-align: right; font-weight: bold;">' . $report_title . '</div>' );
$mpdf->SetHTMLFooter( '<div style="font-size: 9pt; text-align: center;">Page {PAGENO} of {nbpg} | Generated on ' . date( 'Y-m-d H:i:s' ) . '</div>' );
// Build HTML content
$html = '<h1 style="text-align: center;">' . esc_html( $report_title ) . '</h1>';
$html .= '<p>Report Period: ' . date( 'Y-m-d', strtotime( $_POST['start_date'] ) ) . ' to ' . date( 'Y-m-d', strtotime( $_POST['end_date'] ) ) . '</p>'; // Assuming dates are passed via POST
if ( ! empty( $data ) ) {
$html .= '<table border="1" cellpadding="5" cellspacing="0" style="width: 100%; border-collapse: collapse;">';
$html .= '<thead><tr>';
// Dynamically generate headers from the first row's keys
$headers = array_keys( $data[0] );
foreach ( $headers as $header ) {
$html .= '<th>' . esc_html( ucwords( str_replace( '_', ' ', $header ) ) ) . '</th>';
}
$html .= '</tr></thead><tbody>';
foreach ( $data as $row ) {
$html .= '<tr>';
foreach ( $row as $key => $value ) {
// Format specific fields for better readability
if ( $key === 'timestamp' ) {
$value = date( 'Y-m-d H:i:s', strtotime( $value ) );
} elseif ( $key === 'amount' ) {
$value = number_format( (float) $value, 2 );
}
$html .= '<td>' . esc_html( $value ) . '</td>';
}
$html .= '</tr>';
}
$html .= '</tbody></table>';
} else {
$html .= '<p>No data found for the specified period.</p>';
}
$mpdf->WriteHTML( $html );
// Output the PDF
// You can choose to output directly to browser, save to a file, or return as string
$upload_dir = wp_upload_dir();
$report_filename = sanitize_title( $report_title ) . '_' . date( 'YmdHis' ) . '.pdf';
$file_path = $upload_dir['basedir'] . '/subscription-reports/' . $report_filename;
// Ensure the directory exists
if ( ! file_exists( dirname( $file_path ) ) ) {
wp_mkdir_p( dirname( $file_path ) );
}
$mpdf->Output( $file_path, \Mpdf\Output\Destination::FILE );
return $file_path;
} catch ( \Mpdf\MpdfException $e ) {
// Log the error or handle it appropriately
error_log( 'mPDF Error: ' . $e->getMessage() );
return false;
}
}
}
Admin Interface for Report Generation
To make this user-friendly, we’ll add an admin page where users can select a date range and trigger the report generation. This will be handled by the CSR_Admin class.
// includes/class-csr-admin.php
namespace Antigravity\CSR;
class CSR_Admin {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Admin();
}
return self::$instance;
}
private function __construct() {
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
add_action( 'admin_init', array( $this, 'handle_report_generation' ) );
}
/**
* Adds the admin menu page.
*/
public function add_admin_menu() {
add_menu_page(
__( 'Subscription Reports', 'custom-subscription-reporter' ),
__( 'Subscription Reports', 'custom-subscription-reporter' ),
'manage_options', // Capability required to access
'csr-reports',
array( $this, 'render_report_page' ),
'dashicons-chart-bar', // Icon
80 // Position
);
}
/**
* Renders the HTML for the admin report page.
*/
public function render_report_page() {
?>
Advanced Considerations and Enhancements
This basic implementation can be extended significantly:
- Scheduled Reporting: Integrate with WordPress Cron (WP-Cron) to automatically generate and email reports on a daily, weekly, or monthly basis. This would involve creating a WP-Cron event and a callback function that triggers the report generation and email sending process.
- Customizable Templates: Instead of hardcoding HTML, use a templating engine or WordPress's built-in template hierarchy to allow for more flexible report designs. mPDF supports loading HTML from files.
- Error Handling and Logging: Implement more sophisticated error logging using WordPress's built-in logging functions or a dedicated logging library.
- User Roles and Permissions: Refine access control beyond 'manage_options' to allow specific user roles to generate or view reports.
- Data Filtering and Aggregation: Add options for filtering data by subscription type, user status, or transaction type. Implement summary statistics (e.g., total revenue, number of new subscriptions) within the report.
- Internationalization (i18n): Ensure all user-facing strings are translatable using WordPress's internationalization functions (e.g.,
__(),_e()). - Font Management: Ensure mPDF has access to necessary fonts for different languages. You might need to explicitly configure font paths or embed fonts.
- Security: Always sanitize user inputs and use nonces for form submissions to prevent CSRF attacks. Ensure file permissions are set correctly for the upload directory.
By combining the power of mPDF with a well-structured WordPress plugin, you can create a highly effective and automated system for generating compliance-ready subscription ledger reports, saving significant time and reducing the risk of manual errors.
// custom-subscription-reporter.php
/*
Plugin Name: Custom Subscription Reporter
Description: Automates compliance reporting for custom subscription ledgers.
Version: 1.0
Author: Antigravity
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// Include Composer autoloader
require_once __DIR__ . '/vendor/autoload.php';
// Define constants for clarity
define( 'CSR_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
define( 'CSR_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
// Include core files
require_once CSR_PLUGIN_PATH . 'includes/class-csr-reporting.php';
require_once CSR_PLUGIN_PATH . 'includes/class-csr-admin.php';
// Initialize classes
CSR_Reporting::init();
CSR_Admin::init();
// Activation hook (optional, for initial setup if needed)
register_activation_hook( __FILE__, 'csr_activate_plugin' );
function csr_activate_plugin() {
// Example: Create custom table if it doesn't exist
global $wpdb;
$table_name = $wpdb->prefix . 'subscription_ledger';
$charset_collate = $wpdb->get_charset_collate();
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) != $table_name ) {
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
transaction_id varchar(255) NOT NULL UNIQUE,
user_id bigint(20) unsigned NOT NULL,
subscription_id bigint(20) unsigned NOT NULL,
transaction_type varchar(50) NOT NULL,
amount decimal(10,2) NOT NULL,
timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
status varchar(50) NOT NULL DEFAULT 'completed',
PRIMARY KEY (id),
KEY user_id (user_id),
KEY subscription_id (subscription_id)
) $charset_collate;";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
}
Generating PDF Reports with mPDF
The core logic for report generation will reside in a class, say CSR_Reporting. This class will fetch data from our custom ledger table and use mPDF to render it into a PDF document.
// includes/class-csr-reporting.php
namespace Antigravity\CSR;
use Mpdf\Mpdf;
use WP_Query;
class CSR_Reporting {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Reporting();
}
return self::$instance;
}
private function __construct() {
// Hook into WordPress actions/filters if needed
// For example, to trigger report generation via an AJAX call or a cron job
}
/**
* Fetches subscription ledger data for a given date range.
*
* @param string $start_date Start date in YYYY-MM-DD format.
* @param string $end_date End date in YYYY-MM-DD format.
* @return array Array of ledger entries.
*/
public function get_ledger_data( $start_date, $end_date ) {
global $wpdb;
$table_name = $wpdb->prefix . 'subscription_ledger';
$sql = $wpdb->prepare(
"SELECT * FROM {$table_name}
WHERE DATE(timestamp) BETWEEN %s AND %s
ORDER BY timestamp ASC",
$start_date,
$end_date
);
$results = $wpdb->get_results( $sql, ARRAY_A );
return $results;
}
/**
* Generates a PDF report using mPDF.
*
* @param array $data Ledger data to include in the report.
* @param string $report_title Title for the report.
* @return string Path to the generated PDF file.
*/
public function generate_pdf_report( $data, $report_title = 'Subscription Ledger Report' ) {
try {
$mpdf = new Mpdf( [
'mode' => 'utf-8',
'format' => 'A4',
'margin_left' => 15,
'margin_right' => 15,
'margin_top' => 16,
'margin_bottom' => 16,
'margin_header' => 9,
'margin_footer' => 9,
'default_font_size' => 10,
'default_font' => 'dejavusans', // Ensure this font is available or install it
] );
// Set document metadata
$mpdf->SetTitle( $report_title );
$mpdf->SetAuthor( 'Your Company Name' );
$mpdf->SetCreator( 'Custom Subscription Reporter Plugin' );
// Add header and footer
$mpdf->SetHTMLHeader( '<div style="text-align: right; font-weight: bold;">' . $report_title . '</div>' );
$mpdf->SetHTMLFooter( '<div style="font-size: 9pt; text-align: center;">Page {PAGENO} of {nbpg} | Generated on ' . date( 'Y-m-d H:i:s' ) . '</div>' );
// Build HTML content
$html = '<h1 style="text-align: center;">' . esc_html( $report_title ) . '</h1>';
$html .= '<p>Report Period: ' . date( 'Y-m-d', strtotime( $_POST['start_date'] ) ) . ' to ' . date( 'Y-m-d', strtotime( $_POST['end_date'] ) ) . '</p>'; // Assuming dates are passed via POST
if ( ! empty( $data ) ) {
$html .= '<table border="1" cellpadding="5" cellspacing="0" style="width: 100%; border-collapse: collapse;">';
$html .= '<thead><tr>';
// Dynamically generate headers from the first row's keys
$headers = array_keys( $data[0] );
foreach ( $headers as $header ) {
$html .= '<th>' . esc_html( ucwords( str_replace( '_', ' ', $header ) ) ) . '</th>';
}
$html .= '</tr></thead><tbody>';
foreach ( $data as $row ) {
$html .= '<tr>';
foreach ( $row as $key => $value ) {
// Format specific fields for better readability
if ( $key === 'timestamp' ) {
$value = date( 'Y-m-d H:i:s', strtotime( $value ) );
} elseif ( $key === 'amount' ) {
$value = number_format( (float) $value, 2 );
}
$html .= '<td>' . esc_html( $value ) . '</td>';
}
$html .= '</tr>';
}
$html .= '</tbody></table>';
} else {
$html .= '<p>No data found for the specified period.</p>';
}
$mpdf->WriteHTML( $html );
// Output the PDF
// You can choose to output directly to browser, save to a file, or return as string
$upload_dir = wp_upload_dir();
$report_filename = sanitize_title( $report_title ) . '_' . date( 'YmdHis' ) . '.pdf';
$file_path = $upload_dir['basedir'] . '/subscription-reports/' . $report_filename;
// Ensure the directory exists
if ( ! file_exists( dirname( $file_path ) ) ) {
wp_mkdir_p( dirname( $file_path ) );
}
$mpdf->Output( $file_path, \Mpdf\Output\Destination::FILE );
return $file_path;
} catch ( \Mpdf\MpdfException $e ) {
// Log the error or handle it appropriately
error_log( 'mPDF Error: ' . $e->getMessage() );
return false;
}
}
}
Admin Interface for Report Generation
To make this user-friendly, we'll add an admin page where users can select a date range and trigger the report generation. This will be handled by the CSR_Admin class.
// includes/class-csr-admin.php
namespace Antigravity\CSR;
class CSR_Admin {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Admin();
}
return self::$instance;
}
private function __construct() {
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
add_action( 'admin_init', array( $this, 'handle_report_generation' ) );
}
/**
* Adds the admin menu page.
*/
public function add_admin_menu() {
add_menu_page(
__( 'Subscription Reports', 'custom-subscription-reporter' ),
__( 'Subscription Reports', 'custom-subscription-reporter' ),
'manage_options', // Capability required to access
'csr-reports',
array( $this, 'render_report_page' ),
'dashicons-chart-bar', // Icon
80 // Position
);
}
/**
* Renders the HTML for the admin report page.
*/
public function render_report_page() {
?>
Advanced Considerations and Enhancements
This basic implementation can be extended significantly:
- Scheduled Reporting: Integrate with WordPress Cron (WP-Cron) to automatically generate and email reports on a daily, weekly, or monthly basis. This would involve creating a WP-Cron event and a callback function that triggers the report generation and email sending process.
- Customizable Templates: Instead of hardcoding HTML, use a templating engine or WordPress's built-in template hierarchy to allow for more flexible report designs. mPDF supports loading HTML from files.
- Error Handling and Logging: Implement more sophisticated error logging using WordPress's built-in logging functions or a dedicated logging library.
- User Roles and Permissions: Refine access control beyond 'manage_options' to allow specific user roles to generate or view reports.
- Data Filtering and Aggregation: Add options for filtering data by subscription type, user status, or transaction type. Implement summary statistics (e.g., total revenue, number of new subscriptions) within the report.
- Internationalization (i18n): Ensure all user-facing strings are translatable using WordPress's internationalization functions (e.g.,
__(),_e()). - Font Management: Ensure mPDF has access to necessary fonts for different languages. You might need to explicitly configure font paths or embed fonts.
- Security: Always sanitize user inputs and use nonces for form submissions to prevent CSRF attacks. Ensure file permissions are set correctly for the upload directory.
By combining the power of mPDF with a well-structured WordPress plugin, you can create a highly effective and automated system for generating compliance-ready subscription ledger reports, saving significant time and reducing the risk of manual errors.
composer require mpdf/mpdf
This will create a vendor directory and download mPDF and its dependencies. You'll need to include the Composer autoloader in your plugin's main file.
Plugin Structure and Core Components
We'll create a simple WordPress plugin. Let's assume the main plugin file is custom-subscription-reporter.php.
// custom-subscription-reporter.php
/*
Plugin Name: Custom Subscription Reporter
Description: Automates compliance reporting for custom subscription ledgers.
Version: 1.0
Author: Antigravity
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// Include Composer autoloader
require_once __DIR__ . '/vendor/autoload.php';
// Define constants for clarity
define( 'CSR_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
define( 'CSR_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
// Include core files
require_once CSR_PLUGIN_PATH . 'includes/class-csr-reporting.php';
require_once CSR_PLUGIN_PATH . 'includes/class-csr-admin.php';
// Initialize classes
CSR_Reporting::init();
CSR_Admin::init();
// Activation hook (optional, for initial setup if needed)
register_activation_hook( __FILE__, 'csr_activate_plugin' );
function csr_activate_plugin() {
// Example: Create custom table if it doesn't exist
global $wpdb;
$table_name = $wpdb->prefix . 'subscription_ledger';
$charset_collate = $wpdb->get_charset_collate();
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) != $table_name ) {
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
transaction_id varchar(255) NOT NULL UNIQUE,
user_id bigint(20) unsigned NOT NULL,
subscription_id bigint(20) unsigned NOT NULL,
transaction_type varchar(50) NOT NULL,
amount decimal(10,2) NOT NULL,
timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
status varchar(50) NOT NULL DEFAULT 'completed',
PRIMARY KEY (id),
KEY user_id (user_id),
KEY subscription_id (subscription_id)
) $charset_collate;";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
}
Generating PDF Reports with mPDF
The core logic for report generation will reside in a class, say CSR_Reporting. This class will fetch data from our custom ledger table and use mPDF to render it into a PDF document.
// includes/class-csr-reporting.php
namespace Antigravity\CSR;
use Mpdf\Mpdf;
use WP_Query;
class CSR_Reporting {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Reporting();
}
return self::$instance;
}
private function __construct() {
// Hook into WordPress actions/filters if needed
// For example, to trigger report generation via an AJAX call or a cron job
}
/**
* Fetches subscription ledger data for a given date range.
*
* @param string $start_date Start date in YYYY-MM-DD format.
* @param string $end_date End date in YYYY-MM-DD format.
* @return array Array of ledger entries.
*/
public function get_ledger_data( $start_date, $end_date ) {
global $wpdb;
$table_name = $wpdb->prefix . 'subscription_ledger';
$sql = $wpdb->prepare(
"SELECT * FROM {$table_name}
WHERE DATE(timestamp) BETWEEN %s AND %s
ORDER BY timestamp ASC",
$start_date,
$end_date
);
$results = $wpdb->get_results( $sql, ARRAY_A );
return $results;
}
/**
* Generates a PDF report using mPDF.
*
* @param array $data Ledger data to include in the report.
* @param string $report_title Title for the report.
* @return string Path to the generated PDF file.
*/
public function generate_pdf_report( $data, $report_title = 'Subscription Ledger Report' ) {
try {
$mpdf = new Mpdf( [
'mode' => 'utf-8',
'format' => 'A4',
'margin_left' => 15,
'margin_right' => 15,
'margin_top' => 16,
'margin_bottom' => 16,
'margin_header' => 9,
'margin_footer' => 9,
'default_font_size' => 10,
'default_font' => 'dejavusans', // Ensure this font is available or install it
] );
// Set document metadata
$mpdf->SetTitle( $report_title );
$mpdf->SetAuthor( 'Your Company Name' );
$mpdf->SetCreator( 'Custom Subscription Reporter Plugin' );
// Add header and footer
$mpdf->SetHTMLHeader( '<div style="text-align: right; font-weight: bold;">' . $report_title . '</div>' );
$mpdf->SetHTMLFooter( '<div style="font-size: 9pt; text-align: center;">Page {PAGENO} of {nbpg} | Generated on ' . date( 'Y-m-d H:i:s' ) . '</div>' );
// Build HTML content
$html = '<h1 style="text-align: center;">' . esc_html( $report_title ) . '</h1>';
$html .= '<p>Report Period: ' . date( 'Y-m-d', strtotime( $_POST['start_date'] ) ) . ' to ' . date( 'Y-m-d', strtotime( $_POST['end_date'] ) ) . '</p>'; // Assuming dates are passed via POST
if ( ! empty( $data ) ) {
$html .= '<table border="1" cellpadding="5" cellspacing="0" style="width: 100%; border-collapse: collapse;">';
$html .= '<thead><tr>';
// Dynamically generate headers from the first row's keys
$headers = array_keys( $data[0] );
foreach ( $headers as $header ) {
$html .= '<th>' . esc_html( ucwords( str_replace( '_', ' ', $header ) ) ) . '</th>';
}
$html .= '</tr></thead><tbody>';
foreach ( $data as $row ) {
$html .= '<tr>';
foreach ( $row as $key => $value ) {
// Format specific fields for better readability
if ( $key === 'timestamp' ) {
$value = date( 'Y-m-d H:i:s', strtotime( $value ) );
} elseif ( $key === 'amount' ) {
$value = number_format( (float) $value, 2 );
}
$html .= '<td>' . esc_html( $value ) . '</td>';
}
$html .= '</tr>';
}
$html .= '</tbody></table>';
} else {
$html .= '<p>No data found for the specified period.</p>';
}
$mpdf->WriteHTML( $html );
// Output the PDF
// You can choose to output directly to browser, save to a file, or return as string
$upload_dir = wp_upload_dir();
$report_filename = sanitize_title( $report_title ) . '_' . date( 'YmdHis' ) . '.pdf';
$file_path = $upload_dir['basedir'] . '/subscription-reports/' . $report_filename;
// Ensure the directory exists
if ( ! file_exists( dirname( $file_path ) ) ) {
wp_mkdir_p( dirname( $file_path ) );
}
$mpdf->Output( $file_path, \Mpdf\Output\Destination::FILE );
return $file_path;
} catch ( \Mpdf\MpdfException $e ) {
// Log the error or handle it appropriately
error_log( 'mPDF Error: ' . $e->getMessage() );
return false;
}
}
}
Admin Interface for Report Generation
To make this user-friendly, we'll add an admin page where users can select a date range and trigger the report generation. This will be handled by the CSR_Admin class.
// includes/class-csr-admin.php
namespace Antigravity\CSR;
class CSR_Admin {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Admin();
}
return self::$instance;
}
private function __construct() {
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
add_action( 'admin_init', array( $this, 'handle_report_generation' ) );
}
/**
* Adds the admin menu page.
*/
public function add_admin_menu() {
add_menu_page(
__( 'Subscription Reports', 'custom-subscription-reporter' ),
__( 'Subscription Reports', 'custom-subscription-reporter' ),
'manage_options', // Capability required to access
'csr-reports',
array( $this, 'render_report_page' ),
'dashicons-chart-bar', // Icon
80 // Position
);
}
/**
* Renders the HTML for the admin report page.
*/
public function render_report_page() {
?>
Advanced Considerations and Enhancements
This basic implementation can be extended significantly:
- Scheduled Reporting: Integrate with WordPress Cron (WP-Cron) to automatically generate and email reports on a daily, weekly, or monthly basis. This would involve creating a WP-Cron event and a callback function that triggers the report generation and email sending process.
- Customizable Templates: Instead of hardcoding HTML, use a templating engine or WordPress's built-in template hierarchy to allow for more flexible report designs. mPDF supports loading HTML from files.
- Error Handling and Logging: Implement more sophisticated error logging using WordPress's built-in logging functions or a dedicated logging library.
- User Roles and Permissions: Refine access control beyond 'manage_options' to allow specific user roles to generate or view reports.
- Data Filtering and Aggregation: Add options for filtering data by subscription type, user status, or transaction type. Implement summary statistics (e.g., total revenue, number of new subscriptions) within the report.
- Internationalization (i18n): Ensure all user-facing strings are translatable using WordPress's internationalization functions (e.g.,
__(),_e()). - Font Management: Ensure mPDF has access to necessary fonts for different languages. You might need to explicitly configure font paths or embed fonts.
- Security: Always sanitize user inputs and use nonces for form submissions to prevent CSRF attacks. Ensure file permissions are set correctly for the upload directory.
By combining the power of mPDF with a well-structured WordPress plugin, you can create a highly effective and automated system for generating compliance-ready subscription ledger reports, saving significant time and reducing the risk of manual errors.
Leveraging mPDF for Automated Subscription Ledger Compliance Reporting
For WordPress sites managing custom subscription models, maintaining auditable and compliant ledgers is paramount. This often involves generating periodic reports that detail subscription status, payments, and user activity. While manual report generation is feasible for small operations, scaling requires automation. This post details a robust approach to automating compliance reporting using the mPDF library, integrated within a custom WordPress plugin.
Prerequisites and Setup
Before diving into the implementation, ensure you have the following:
- A WordPress installation with administrative access.
- PHP 7.4+ with Composer installed.
- Basic understanding of WordPress plugin development and custom database tables.
- A custom database table (e.g.,
wp_subscription_ledger) to store subscription transaction data. This table should include fields liketransaction_id,user_id,subscription_id,transaction_type(e.g., 'subscribe', 'renew', 'cancel', 'payment'),amount,timestamp, andstatus.
We'll use Composer to manage the mPDF dependency. Navigate to your plugin's root directory in your terminal and run:
composer require mpdf/mpdf
This will create a vendor directory and download mPDF and its dependencies. You'll need to include the Composer autoloader in your plugin's main file.
Plugin Structure and Core Components
We'll create a simple WordPress plugin. Let's assume the main plugin file is custom-subscription-reporter.php.
// custom-subscription-reporter.php
/*
Plugin Name: Custom Subscription Reporter
Description: Automates compliance reporting for custom subscription ledgers.
Version: 1.0
Author: Antigravity
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// Include Composer autoloader
require_once __DIR__ . '/vendor/autoload.php';
// Define constants for clarity
define( 'CSR_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
define( 'CSR_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
// Include core files
require_once CSR_PLUGIN_PATH . 'includes/class-csr-reporting.php';
require_once CSR_PLUGIN_PATH . 'includes/class-csr-admin.php';
// Initialize classes
CSR_Reporting::init();
CSR_Admin::init();
// Activation hook (optional, for initial setup if needed)
register_activation_hook( __FILE__, 'csr_activate_plugin' );
function csr_activate_plugin() {
// Example: Create custom table if it doesn't exist
global $wpdb;
$table_name = $wpdb->prefix . 'subscription_ledger';
$charset_collate = $wpdb->get_charset_collate();
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) != $table_name ) {
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
transaction_id varchar(255) NOT NULL UNIQUE,
user_id bigint(20) unsigned NOT NULL,
subscription_id bigint(20) unsigned NOT NULL,
transaction_type varchar(50) NOT NULL,
amount decimal(10,2) NOT NULL,
timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
status varchar(50) NOT NULL DEFAULT 'completed',
PRIMARY KEY (id),
KEY user_id (user_id),
KEY subscription_id (subscription_id)
) $charset_collate;";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
}
Generating PDF Reports with mPDF
The core logic for report generation will reside in a class, say CSR_Reporting. This class will fetch data from our custom ledger table and use mPDF to render it into a PDF document.
// includes/class-csr-reporting.php
namespace Antigravity\CSR;
use Mpdf\Mpdf;
use WP_Query;
class CSR_Reporting {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Reporting();
}
return self::$instance;
}
private function __construct() {
// Hook into WordPress actions/filters if needed
// For example, to trigger report generation via an AJAX call or a cron job
}
/**
* Fetches subscription ledger data for a given date range.
*
* @param string $start_date Start date in YYYY-MM-DD format.
* @param string $end_date End date in YYYY-MM-DD format.
* @return array Array of ledger entries.
*/
public function get_ledger_data( $start_date, $end_date ) {
global $wpdb;
$table_name = $wpdb->prefix . 'subscription_ledger';
$sql = $wpdb->prepare(
"SELECT * FROM {$table_name}
WHERE DATE(timestamp) BETWEEN %s AND %s
ORDER BY timestamp ASC",
$start_date,
$end_date
);
$results = $wpdb->get_results( $sql, ARRAY_A );
return $results;
}
/**
* Generates a PDF report using mPDF.
*
* @param array $data Ledger data to include in the report.
* @param string $report_title Title for the report.
* @return string Path to the generated PDF file.
*/
public function generate_pdf_report( $data, $report_title = 'Subscription Ledger Report' ) {
try {
$mpdf = new Mpdf( [
'mode' => 'utf-8',
'format' => 'A4',
'margin_left' => 15,
'margin_right' => 15,
'margin_top' => 16,
'margin_bottom' => 16,
'margin_header' => 9,
'margin_footer' => 9,
'default_font_size' => 10,
'default_font' => 'dejavusans', // Ensure this font is available or install it
] );
// Set document metadata
$mpdf->SetTitle( $report_title );
$mpdf->SetAuthor( 'Your Company Name' );
$mpdf->SetCreator( 'Custom Subscription Reporter Plugin' );
// Add header and footer
$mpdf->SetHTMLHeader( '<div style="text-align: right; font-weight: bold;">' . $report_title . '</div>' );
$mpdf->SetHTMLFooter( '<div style="font-size: 9pt; text-align: center;">Page {PAGENO} of {nbpg} | Generated on ' . date( 'Y-m-d H:i:s' ) . '</div>' );
// Build HTML content
$html = '<h1 style="text-align: center;">' . esc_html( $report_title ) . '</h1>';
$html .= '<p>Report Period: ' . date( 'Y-m-d', strtotime( $_POST['start_date'] ) ) . ' to ' . date( 'Y-m-d', strtotime( $_POST['end_date'] ) ) . '</p>'; // Assuming dates are passed via POST
if ( ! empty( $data ) ) {
$html .= '<table border="1" cellpadding="5" cellspacing="0" style="width: 100%; border-collapse: collapse;">';
$html .= '<thead><tr>';
// Dynamically generate headers from the first row's keys
$headers = array_keys( $data[0] );
foreach ( $headers as $header ) {
$html .= '<th>' . esc_html( ucwords( str_replace( '_', ' ', $header ) ) ) . '</th>';
}
$html .= '</tr></thead><tbody>';
foreach ( $data as $row ) {
$html .= '<tr>';
foreach ( $row as $key => $value ) {
// Format specific fields for better readability
if ( $key === 'timestamp' ) {
$value = date( 'Y-m-d H:i:s', strtotime( $value ) );
} elseif ( $key === 'amount' ) {
$value = number_format( (float) $value, 2 );
}
$html .= '<td>' . esc_html( $value ) . '</td>';
}
$html .= '</tr>';
}
$html .= '</tbody></table>';
} else {
$html .= '<p>No data found for the specified period.</p>';
}
$mpdf->WriteHTML( $html );
// Output the PDF
// You can choose to output directly to browser, save to a file, or return as string
$upload_dir = wp_upload_dir();
$report_filename = sanitize_title( $report_title ) . '_' . date( 'YmdHis' ) . '.pdf';
$file_path = $upload_dir['basedir'] . '/subscription-reports/' . $report_filename;
// Ensure the directory exists
if ( ! file_exists( dirname( $file_path ) ) ) {
wp_mkdir_p( dirname( $file_path ) );
}
$mpdf->Output( $file_path, \Mpdf\Output\Destination::FILE );
return $file_path;
} catch ( \Mpdf\MpdfException $e ) {
// Log the error or handle it appropriately
error_log( 'mPDF Error: ' . $e->getMessage() );
return false;
}
}
}
Admin Interface for Report Generation
To make this user-friendly, we'll add an admin page where users can select a date range and trigger the report generation. This will be handled by the CSR_Admin class.
// includes/class-csr-admin.php
namespace Antigravity\CSR;
class CSR_Admin {
private static $instance;
public static function init() {
if ( self::$instance == null ) {
self::$instance = new CSR_Admin();
}
return self::$instance;
}
private function __construct() {
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
add_action( 'admin_init', array( $this, 'handle_report_generation' ) );
}
/**
* Adds the admin menu page.
*/
public function add_admin_menu() {
add_menu_page(
__( 'Subscription Reports', 'custom-subscription-reporter' ),
__( 'Subscription Reports', 'custom-subscription-reporter' ),
'manage_options', // Capability required to access
'csr-reports',
array( $this, 'render_report_page' ),
'dashicons-chart-bar', // Icon
80 // Position
);
}
/**
* Renders the HTML for the admin report page.
*/
public function render_report_page() {
?>
Advanced Considerations and Enhancements
This basic implementation can be extended significantly:
- Scheduled Reporting: Integrate with WordPress Cron (WP-Cron) to automatically generate and email reports on a daily, weekly, or monthly basis. This would involve creating a WP-Cron event and a callback function that triggers the report generation and email sending process.
- Customizable Templates: Instead of hardcoding HTML, use a templating engine or WordPress's built-in template hierarchy to allow for more flexible report designs. mPDF supports loading HTML from files.
- Error Handling and Logging: Implement more sophisticated error logging using WordPress's built-in logging functions or a dedicated logging library.
- User Roles and Permissions: Refine access control beyond 'manage_options' to allow specific user roles to generate or view reports.
- Data Filtering and Aggregation: Add options for filtering data by subscription type, user status, or transaction type. Implement summary statistics (e.g., total revenue, number of new subscriptions) within the report.
- Internationalization (i18n): Ensure all user-facing strings are translatable using WordPress's internationalization functions (e.g.,
__(),_e()). - Font Management: Ensure mPDF has access to necessary fonts for different languages. You might need to explicitly configure font paths or embed fonts.
- Security: Always sanitize user inputs and use nonces for form submissions to prevent CSRF attacks. Ensure file permissions are set correctly for the upload directory.
By combining the power of mPDF with a well-structured WordPress plugin, you can create a highly effective and automated system for generating compliance-ready subscription ledger reports, saving significant time and reducing the risk of manual errors.