ActiveOHS: Credential Export Tool

Custom WordPress plugin that turned a complex relational training credential database into a one-click compliance-ready CSV export - replacing a multi-hour manual process with a single admin action.

Overview

Occupational Health & Safety - Training Credential Management

ActiveOHS ran a WordPress-based platform managing occupational health and safety training credentials across Canada. The platform tracked a rich web of data: students, courses, certifications, instructors, course providers, and expiry dates. Every credential record linked outward to a course, a course provider, and an instructor - and inward to a student with employment and enrollment details.

Managing that network inside WordPress was workable. Getting data out of it was not.

For an occupational health and safety platform, reliable data export is not a convenience feature - it is a compliance requirement. Regulators, clients, and insurers all require documented proof that certifications are current and that training records are complete. Before this tool, producing that proof meant manual lookups across multiple WP admin screens, copying data into spreadsheets by hand. Any manual step introduces transcription errors. Any transcription error in a compliance record creates an audit risk.

The core technical problem was relational complexity. No off-the-shelf WordPress export plugin could traverse ACF relationship fields across four linked post types and flatten them into a single exportable row. Generic CSV plugins output one post type at a time - writing five separate exports and manually merging them was not a solution, it was the same manual process with extra steps.

The export was designed as a single-pass operation with a stateless download architecture - no temp files, no session state, no partial downloads if the handler timed out mid-write.

Single WP_Query Pass Across 5 Post Types

One WP_Query loop iterates over all credential records. For each credential, the linked course, course provider, instructor, and student are resolved via their ACF relationship field IDs. All 26 columns are assembled in memory for each row before anything is written - no multiple queries, no post-processing joins.

26-Column Compliance Spec

The column specification was defined by working through actual compliance requirements: what does a regulator ask for? What does an auditor need to verify a certification is valid? What does an HR team need to process an employee record? The export covers enrollment date, course name and code, course provider name and contact details, instructor name and certification number, credential issue date, expiry date, and a calculated lapsed status.

Stateless Download Architecture

The query result set is serialized into a hidden POST field and passed to a standalone download handler that writes directly to php://output with correct Content-Disposition headers. Nothing is written to the server filesystem. No session state required. No risk of a partial file if the handler times out.

Human-Readable Column Headers

Raw ACF field keys mapped to labeled CSV columns matching the format expected by auditors and HR systems. The file opens in any spreadsheet application and is immediately usable by external recipients without explanation or reformatting.

Zero New Dependencies

Built entirely on WP_Query, get_post_meta(), and native PHP fputcsv/fpassthru - no new plugin dependencies, no external services, no intermediate file storage. Works within the existing WordPress installation.

Admin UI

An admin navigates to the export screen, clicks Export, and the browser downloads the file immediately. No configuration required, no options to set, no opportunity for user error in the export process itself.

Compliance reports that previously required assembling data by hand across dozens of WP admin screens - opening individual records one at a time and copying values into a spreadsheet - could now be produced in seconds, with no risk of manual transcription error, in a format immediately usable by external auditors, HR systems, and insurance providers.

The tool did not change how ActiveOHS managed credentials. It changed what the platform could prove. The difference between a credential management system and a compliance-ready system is the ability to produce evidence on demand, in the format a regulator or auditor expects, without manual intervention.

ACF Relationship Field Resolution

Each credential’s linked post IDs (course, provider, instructor, student) are resolved using get_field() with the ACF relationship field name, returning the linked post object directly. No secondary WP_Query needed for relationship resolution within the main loop.

Serialization Approach

The complete result set (array of row arrays) is passed between the export screen and download handler via a base64-encoded, serialized POST payload in a hidden form field. This avoids transient storage and keeps the download handler stateless.

fpassthru vs fputcsv

Each row is written via fputcsv() to a PHP output buffer opened with fopen(‘php://output’, ‘w’). fpassthru() is not used - fputcsv() handles quoting and escaping correctly for CSV compliance, which matters for fields containing commas (course provider addresses, instructor notes).

Column Header Mapping

A static associative array maps ACF field keys to human-readable column headers. This is defined once at the top of the export class and used both to write the header row and to ensure consistent column ordering regardless of the order fields are resolved from ACF.

Client: ActiveOHS

Location: Canada

The Challenge & Solution

No Way to Extract Data from a Complex Credential Management System

ActiveOHS ran a WordPress-based platform managing occupational health and safety training credentials across Canada. The platform tracked a rich web of data: students, courses, certifications, instructors, course providers, and expiry dates. Every credential record linked outward to a course, a course provider, and an instructor - and inward to a student with employment and enrollment details.

Managing that network inside WordPress was workable. Getting data out of it was not.

For an occupational health and safety platform, reliable data export is not a convenience feature - it is a compliance requirement. Regulators, clients, and insurers all require documented proof that certifications are current and that training records are complete. Before this tool, producing that proof meant manual lookups across multiple WP admin screens, copying data into spreadsheets by hand. Any manual step introduces transcription errors. Any transcription error in a compliance record creates an audit risk.

The core technical problem was relational complexity. No off-the-shelf WordPress export plugin could traverse ACF relationship fields across four linked post types and flatten them into a single exportable row. Generic CSV plugins output one post type at a time - writing five separate exports and manually merging them was not a solution, it was the same manual process with extra steps.

Technical Highlights

The export was designed as a single-pass operation with a stateless download architecture - no temp files, no session state, no partial downloads if the handler timed out mid-write.

Single WP_Query Pass Across 5 Post Types

One WP_Query loop iterates over all credential records. For each credential, the linked course, course provider, instructor, and student are resolved via their ACF relationship field IDs. All 26 columns are assembled in memory for each row before anything is written - no multiple queries, no post-processing joins.

26-Column Compliance Spec

The column specification was defined by working through actual compliance requirements: what does a regulator ask for? What does an auditor need to verify a certification is valid? What does an HR team need to process an employee record? The export covers enrollment date, course name and code, course provider name and contact details, instructor name and certification number, credential issue date, expiry date, and a calculated lapsed status.

Stateless Download Architecture

The query result set is serialized into a hidden POST field and passed to a standalone download handler that writes directly to php://output with correct Content-Disposition headers. Nothing is written to the server filesystem. No session state required. No risk of a partial file if the handler times out.

Human-Readable Column Headers

Raw ACF field keys mapped to labeled CSV columns matching the format expected by auditors and HR systems. The file opens in any spreadsheet application and is immediately usable by external recipients without explanation or reformatting.

Zero New Dependencies

Built entirely on WP_Query, get_post_meta(), and native PHP fputcsv/fpassthru - no new plugin dependencies, no external services, no intermediate file storage. Works within the existing WordPress installation.

Admin UI

An admin navigates to the export screen, clicks Export, and the browser downloads the file immediately. No configuration required, no options to set, no opportunity for user error in the export process itself.

Challenge & Solution
Dejan Markovic
Dejan Markovic WordPress Architect
Best experience I've had to date with someone from Codeable. Dejan and his team jumped on a critical project over a weekend and had it sussed and patched on a Sunday; by Monday evening a fix was fully implemented. The team exceeded my expectations and I will be using them for all of my development needs going forward.
Eric R. | CEO & Founder, carsandcoffeeevents.com