Architecture¶
base-plugin is a Composer package (barberklingen/base-plugin) that other Barberklingen/Subscribed plugins require. It contains no WordPress plugin header — it is bootstrapped by the consuming plugin.
Namespace¶
All classes live under Barberklingen\BasePlugin\ with PSR-4 autoloading from src/.
Bootstrap¶
// 1. Build the League Container and register the global singleton
GlobalContainer::get_instance()->setup($container, new MyAppConfig());
// 2. Init core modules (migrations, admin hooks, renewals, staging CLI)
BasePluginSetup::get_instance()->init();
Directory structure¶
src/
├── DependencyManagement/ League Container wrapper + AppConfig interface
├── Migrations/ Database migration runner (versioned)
├── Modules/ Feature modules (see below)
├── Storage/ ORM-style base classes
├── Traits/ Reusable traits (Module, Singleton, Scheduler, …)
├── Data/ Frontend data-transfer objects
├── Frontend/ Asset enqueueing + template loading
├── Helpers/ Stateless utility classes
├── Http/ HTTP controller base
├── REST/ REST route base classes
├── Payments/ Payment handler contract
├── Staging/ CLI command for staging data pull
├── Exceptions/ Custom exception types
└── functions.php Global helper functions
Dependency Injection¶
GlobalContainer wraps a League Container singleton. Consuming plugins call addProviders() to register their own service providers before modules are initialised.
AppConfig / AppConfigInterface carry environment-specific configuration (URLs, API keys, feature flags) and are bound to the container so any class can resolve them.
Migrations¶
Migrator (trait) runs versioned migrations on plugins_loaded. Each migration implements Migration and is listed in the migrator's get_migrations() array. The current version is stored in wp_options.
RecurringTasksMigrator registers WP-Cron schedules and recurring tasks.
Storage layer¶
| Class / trait | Purpose |
|---|---|
BaseModel | Active-record trait: save(), delegates to store |
BaseStore | CRUD operations against a custom DB table |
ORMModel | Extends BaseModel with typed property casting |
ORMModelWithMeta | Adds a MetaData side-table for arbitrary key/value pairs |
LookupCache | In-request cache for repeated store lookups |
Key modules¶
| Module | Description |
|---|---|
SubscriptionAddons | Addon products attached to subscriptions; handles cart, renewals, admin UI, Klaviyo/GTM events |
SubscriptionRenewals | Custom renewal logic with status tracking; CLI command to cancel unpaid orders |
ReferralCoupons | Generate, list and validate referral coupons; WP-CLI commands |
ReplacementOrder | Replace an existing order via REST endpoint; Klaviyo extension |
Security | Role/capability management (customer service, finance, warehouse, etc.); area-based lockdown |
Ajax/* | AJAX checkout flow (setup → order/subscription), cart update, account actions |
REST | Base RouteController / RouteSchema for registering REST routes |
Frontend | Asset enqueueing, JS globals (GlobalAppJS), template rendering |
Traits¶
| Trait | Description |
|---|---|
Singleton | get_instance() pattern |
Module | Calls init() from constructor; one-time initialisation guard |
Scheduler | Cron-job wrapper with distributed process lock (bypasses Redis object cache for the lock) |
AjaxEndpoint | Registers wp_ajax_* / wp_ajax_nopriv_* hooks |
WCAPIEndpoint | Registers WooCommerce REST routes |
Scheduler flow¶
sequenceDiagram
participant WP as WP-Cron
participant S as Scheduler (trait)
participant DB as wp_options (lock)
WP->>S: system_cron_job_org action
S->>S: maybe_start_scheduler()
S->>DB: read lock directly (bypasses Redis cache)
alt lock free
S->>DB: set lock
S->>S: scheduler_logic()
S->>DB: release lock
else already running
S-->>WP: SchedulerAlreadyRunningException (NOOP)
end