Plugin Architecture

Get Started

Plugin Architecture

Overview

LearnDash Dashboard is a WordPress plugin that extends LearnDash LMS with a frontend dashboard panel. It provides role-specific interfaces for administrators, instructors, group leaders, and students.

Key stats: 28 frontend tabs, 49 AJAX handlers, 17 REST endpoints, 16 admin pages, 9 database tables, 7 cron jobs, 38+ classes.

Requirements: LearnDash LMS (sfwd-lms), ACF PRO.


Directory Structure

ld-dashboard/
├── ld-dashboard.php              # Plugin entry point
├── admin/
│   ├── class-ld-dashboard-admin.php
│   ├── fields/                   # ACF field registration (Field Builder)
│   └── partials/                 # Admin settings templates
├── includes/
│   ├── class-ld-dashboard.php    # Core loader
│   ├── class-ld-dashboard-functions.php
│   ├── emails/                   # Email template system
│   ├── modules/                  # Feature modules (Zoom, BuddyPress, To-Do)
│   ├── reports/                  # Reports + charts architecture
│   ├── save-handlers/            # Form save handlers
│   └── tabs/                     # Instructor tab renderers
├── public/
│   ├── class-ld-dashboard-public.php
│   ├── css/                      # Frontend CSS modules
│   ├── js/                       # Frontend JS modules
│   └── reports/                  # User statistics REST endpoint
├── shortcodes/                   # Legacy shortcode implementations
├── templates/
│   └── emails/                   # Email HTML templates
└── widgets/                      # WordPress widgets

Design Patterns

Singleton

Used for classes that should have only one instance throughout the request lifecycle.

// Access a singleton
$commission = LD_Dashboard_Commission::instance();
$shortcodes = Ld_Dashboard_Shortcodes::instance();
$email      = LD_Dashboard_Email_Template::instance();

Singleton classes: LD<em>Dashboard</em>Commission, LD<em>Dashboard</em>ACF<em>Renderer, LD</em>Dashboard<em>Activity</em>Reporter, Ld<em>Dashboard</em>Shortcodes, LD<em>Dashboard</em>CSS<em>Generator, LD</em>Dashboard<em>Email</em>Handler, LD<em>Dashboard</em>Course<em>Builder, LD</em>Dashboard<em>Instructor</em>Manager, LD<em>Dashboard</em>Assets, LD<em>Dashboard</em>Messaging.

Registry

Central registries manage discovery, instantiation, and REST API routing for reports, charts, tabs, and modules. Each registry is a singleton.

RegistryClassRegistration Hook
Reports + ChartsLD<em>Dashboard</em>Report_Registryld<em>dashboard</em>register<em>reports / ld</em>dashboard<em>register</em>charts
TabsLD<em>Dashboard</em>Tab_Registryld<em>dashboard</em>registered_tabs filter
ModulesLD<em>Dashboard</em>Module_Registryld<em>dashboard</em>register_modules

Template Method

LD<em>Dashboard</em>Tab<em>Base defines the rendering algorithm in its final public function render() method. Subclasses implement the abstract steps (get</em>accessible<em>ids, get</em>filter<em>args, render</em>item) without changing the overall flow.

Builder (Field Builder)

LD<em>Dashboard</em>Field_Builder uses a fluent API to register ACF field groups:

$builder = new LD_Dashboard_Field_Builder( 'lesson' );
$builder
    ->add_title_field( $label )
    ->add_status_field( $label, $statuses )
    ->add_content_field( $label )
    ->register( 'lesson-field-group', $title, $location );

Static Utility Classes

Stateless helper classes accessed via static methods:

LD_Dashboard_Helper::is_instructor( $user_id );
LD_Dashboard_Course_Helper::get_instructor_courses( $user_id );
LD_Dashboard_Query_Helper::get_activity_table_name();

Class Hierarchy

LD_Dashboard_Report_Base (abstract)
└── LD_Dashboard_Chart_Base (abstract)
    ├── LD_Dashboard_Chart_Course_Completion
    ├── LD_Dashboard_Chart_Top_Courses
    ├── LD_Dashboard_Chart_Instructor_Earnings
    └── LD_Dashboard_Chart_Time_Spent
└── LD_Dashboard_Report_Quiz_Results
└── LD_Dashboard_Report_Essay_Submissions
└── LD_Dashboard_Report_Assignment_Status
└── LD_Dashboard_Report_Course_Progress

LD_Dashboard_Module_Base (abstract)
├── LD_Dashboard_Zoom_Module
├── LD_Dashboard_BP_Module
├── LD_Dashboard_Todo_Module
└── LD_Dashboard_Uncanny_Groups_Module

LD_Dashboard_Tab_Base (abstract)
├── LD_Dashboard_Tab_Lesson
├── LD_Dashboard_Tab_Topic
├── LD_Dashboard_Tab_Quiz
├── LD_Dashboard_Tab_Question
├── LD_Dashboard_Tab_Assignment
├── LD_Dashboard_Tab_Announcement
└── LD_Dashboard_Tab_Certificate

LD_Dashboard_Save_Handler_Base (abstract)
├── LD_Dashboard_Save_Handler_Course
├── LD_Dashboard_Save_Handler_Lesson
├── LD_Dashboard_Save_Handler_Topic
├── LD_Dashboard_Save_Handler_Quiz
├── LD_Dashboard_Save_Handler_Question
├── LD_Dashboard_Save_Handler_Certificate
├── LD_Dashboard_Save_Handler_Announcement
└── LD_Dashboard_Save_Handler_Group

Key Entry Points

The plugin boots from ld-dashboard.php which instantiates Ld_Dashboard (the core loader).

ld-dashboard.php
└── Ld_Dashboard (includes/class-ld-dashboard.php)
    ├── loads Admin class       → LD_Dashboard_Admin
    ├── loads Public class      → Ld_Dashboard_Public
    ├── loads Report Registry   → LD_Dashboard_Report_Registry
    ├── loads Module Registry   → LD_Dashboard_Module_Registry
    ├── loads Tab Registry      → LD_Dashboard_Tab_Registry
    ├── loads Messaging         → LD_Dashboard_Messaging
    └── loads REST endpoints    → LD_Dashboard_User_Statistics

Hook Lifecycle

plugins_loaded
  └── Plugin class instantiated
      └── All includes required
          └── Module registry boots (dependency checks)

init (priority 20)
  └── Report Registry initializes
      ├── do_action('ld_dashboard_register_reports', $registry)
      └── do_action('ld_dashboard_register_charts', $registry)

rest_api_init
  └── Report Registry registers REST routes
  └── Messaging registers REST routes
  └── User Statistics registers REST route

wp_enqueue_scripts
  └── LD_Dashboard_Assets enqueues CSS/JS modules

Database Tables

The plugin creates 9 custom tables on activation via dbDelta(). All tables use the WordPress table prefix.

TablePurpose
{prefix}ld<em>dashboard</em>emailsEmail log — records emails sent by instructors to students
{prefix}ld<em>dashboard</em>instructor<em>commission</em>logsCommission transaction records per course sale
{prefix}ld<em>dashboard</em>time_trackingPer-user, per-post time-on-page tracking data
{prefix}ld<em>dashboard</em>invite_userCourse invitation records with acceptance status
{prefix}ld<em>dashboard</em>users_statisticsCached aggregate stats per user (courses, students, etc.)
{prefix}ld<em>dashboard</em>email_queueDB-backed email queue with retry logic and status tracking
{prefix}ld<em>dashboard</em>messagesPrivate messaging threads and replies
{prefix}ld<em>dashboard</em>enrollment_codesEnrollment code batches with usage limits and expiry
{prefix}ld<em>dashboard</em>code_redemptionsRecords of code redemptions per user

Tables are created or updated safely on every plugin activation using dbDelta(), which is safe to re-run on existing tables.

Last updated: March 4, 2026