0006 — Learning Management: Self-Hosted Moodle, Integrated with the Member Portal¶
- Status: Accepted
- Date: 2026-05-09 (revised from earlier TutorLMS draft)
- Decision owners: Gina Lyn Cox · Operations Lead
- Related: ADR-004 (Forms Permissions) · ADR-005 (BuddyBoss Platform) · ADR-007 (Library & Video Hosting) · ADR-008 (Guild ↔ Ganjier Brand Relationship) ·
guildcommerce-core-plugin
Context¶
The Guild needs an LMS to deliver cert-bearing courses, quizzes, certifications, and CE-hour tracking. The LMS must integrate with the member portal — single sign-on, shared brand, shared permission model — so members experience one product, not two.
The Guild operates under a brand license with the Ganjier program (handled by counsel, see ADR-008) but is structurally independent. The Guild does not own Ganjier-program educational content and will not migrate it. The Guild's LMS launches empty and is populated only with Guild-original content.
Cert-bearing content (courses that issue certifications, track CE hours, or validate credentials) must live in a real LMS with a quiz/exam engine, completion tracking, gradebook, and certificate issuance. Non-cert content (Guild Hour replays, resource documents, casual videos) does not need any of that — it just needs to be browseable, searchable, and permission-gated. ADR-007 covers the non-cert side.
Decision¶
Adopt self-hosted Moodle as the Guild's LMS, served at learn.ganjierguild.com, co-located on the existing Cloudways droplet alongside the WordPress member portal. Themed with Boost Union to match the Guild brand. Integrated with the WordPress portal via:
- Single sign-on —
auth_oidcMoodle plugin pairs with an OIDC bridge inguildcommerce-core-plugin. Members logged into the portal land authenticated in Moodle without a second login. - Theme parity — Boost Union (free Moodle theme) loads custom CSS that mirrors
guildcommerce-themecolor tokens, fonts, and visual rhythm. Visually, members shouldn't notice a system change. - Profile widget —
lms-bridgemodule inguildcommerce-core-pluginadds a "My Learning" tab to BuddyBoss profiles showing enrolled courses, progress %, certificates earned, and CE hours total. Data fetched from Moodle's REST API, cached in WordPress. - Completion sync — Moodle webhooks fire on course completion.
lms-bridgewrites a row to thece-ledgermodule capturing course ID, hours, completion date, member ID. CE hours are then visible in the member's profile and used for credentialing reviews. - Certificates —
mod_customcert(free Moodle plugin) issues branded PDF certificates on completion. Certificate URLs sync to WordPress for profile display and download.
The certificate issuance flow uses Moodle's native PDF generation. No Credly, no Accredible. Native PDFs are sufficient for Year 1.
Architecture¶
Member's browser
│
┌───────────┴───────────┐
│ │
▼ ▼
ganjierguild.com learn.ganjierguild.com
(WordPress + BuddyBoss (Moodle + Boost Union theme +
+ guildcommerce-theme + auth_oidc + mod_customcert)
guildcommerce-core-plugin)
│ ▲
│ │
│ OIDC SSO bridge │
├──────────────────────►│
│ │
│ REST API (course │
│ catalog, progress, │
│ enrollment) │
│◄──────────────────────┤
│ │
│ Webhook on │
│ course completion │
│◄──────────────────────┤
│ │
▼ │
guildcommerce-core-plugin │
├── lms-bridge/ │
│ ├── sso-handler.php ──────────┘
│ ├── api-client.php
│ ├── webhook-receiver.php
│ └── profile-tab.php
├── ce-ledger/
│ └── (writes CE hour records on completion)
└── library/ (ADR-007 — non-cert replays + resources)
Both domains are deployed on the Guild's existing Cloudways Autonomous environment. Moodle runs as a separate application with its own database; WordPress runs as the primary application. The two share the same managed Cloudways environment but are otherwise isolated at the application layer.
Hosting decision¶
Deploy Moodle alongside WordPress on the Guild's existing Cloudways Autonomous environment — $0 incremental cost.
Cloudways Autonomous handles traffic scaling and resource allocation at the platform level. Resource pressure from one application does not starve the other in the way a fixed-size droplet would, and adding a second application doesn't require capacity planning the way a managed VPS would.
Justification:
- $0 incremental software, hosting, or scaling cost
- Cloudways Autonomous handles resource scaling automatically; no manual droplet sizing needed
- One managed environment to back up, patch, and monitor
- Subdomain DNS already terminates at Cloudways; adding
learn.ganjierguild.comis a configuration change, not new infrastructure - Application-layer isolation (separate database, separate filesystem path, separate Cloudways app) keeps Moodle and WordPress operationally independent
- SSL, backups, security patching all unified under Cloudways' managed tier
Why self-hosted Moodle¶
| Goal | Self-hosted Moodle | Open LMS | LearnDash | TutorLMS in WP |
|---|---|---|---|---|
| Best-in-class quiz/exam tooling | Yes | Yes (same Moodle core) | Strong | Strong |
| Question banks, randomization, time limits, multiple attempts | Native | Native | Yes | Yes (free tier) |
| Cohort-based enrollment | Native | Native | Add-on | Yes |
| Familiar to founders (Ganjier program uses Moodle) | Yes | Yes | No | No |
| Cost (Year 1) | $0 | $5K–$20K+/yr | $199/yr | $0 |
| Open-source, owned data | Yes | No (vendor lock) | No (vendor) | No (vendor) |
| Native PDF certificates (no per-badge fees) | Yes (mod_customcert) |
Yes | Paid add-on | Free add-on |
| Hosting cost | $0 (co-located) | Bundled | $0 | $0 |
| Same software family as the Ganjier program | Yes | Yes | No | No |
| Operational complexity | Two systems integrated | Two systems integrated | One system | One system |
The deciding factor is Moodle's quiz/exam engine combined with $0 cost. For a credentialing-oriented society, the quiz/exam tooling is the single most important LMS feature, and Moodle leads the field. Open LMS is the same software with a paid wrapper we don't need. LearnDash and TutorLMS are capable but not at Moodle's level for psychometric-grade exam workflows the Guild may eventually adopt.
The two-systems integration burden is real but bounded: SSO + REST API + webhook is well-trodden territory, and Boost Union solves theme parity for free.
Why no Credly / Accredible¶
Native Moodle certificates (via mod_customcert) are sufficient for Year 1. Credly and Accredible cost per badge issued (~$1–$5 each) plus a base fee, and exist primarily to provide portable Open Badge 2.0/3.0 credentials. The Guild's certifications are internally verifiable through the member directory + the issued PDF. If a regulator or accreditor later requires Open Badge issuance, we revisit.
Why no content migration¶
The Guild and the Ganjier program are independent (ADR-008). The Ganjier program's existing Open LMS install is not the Guild's to migrate from. The Guild has no claim on Ganjier-program courses, quiz banks, instructor materials, or member progress data under the current license scope.
This means:
- No
.mbzexports from the Ganjier program's Moodle to the Guild's Moodle - No course rebuilding from Ganjier materials even paraphrased
- No co-branded courses unless the brand license is amended to cover content delivery (would require ADR amendment)
- Existing Ganjier credential holders remain valid — those credentials are issued by the Ganjier program, not the Guild, and remain unaffected
The Guild's Year 1 course roadmap is Guild-original content authored by the Education committee and Guild instructors. Likely categories: governance training for new board members, ethics CE, cannabis-industry business operations, advocacy training, member-portal-onboarding video tour.
Plugins¶
| Moodle plugin | Purpose | Cost |
|---|---|---|
| Boost Union (theme) | Brand parity with guildcommerce-theme; loads custom CSS |
$0 |
auth_oidc |
OIDC SSO from WordPress | $0 |
mod_customcert |
Branded PDF certificate issuance | $0 |
local_webhooks (or built-in event observer) |
Course completion webhook → WordPress | $0 |
All Moodle plugins are free, open-source, and actively maintained.
Cost¶
| Component | Cost |
|---|---|
| Moodle software | $0 |
Boost Union, auth_oidc, mod_customcert, webhook plugin |
$0 |
lms-bridge module in guildcommerce-core-plugin |
$0 (we own it) |
ce-ledger module in guildcommerce-core-plugin |
$0 (we own it) |
| Hosting (Moodle as second app on existing Cloudways Autonomous environment) | $0 incremental |
Domain (learn.ganjierguild.com subdomain) |
$0 (same registration) |
| Total | $0/mo |
Cloudways Autonomous billing scales with actual resource use; adding Moodle as a second application does not introduce a fixed per-droplet line item the way a managed VPS would.
Consequences¶
Positive:
- $0 ongoing software cost; same domain registration
- Same software family as the Ganjier program — familiar to founders
- Best-in-class quiz/exam tooling protects future credentialing workflows
- Owned data, owned infrastructure, no vendor lock
- CE ledger module gives the Guild a first-class, auditable credentialing record
- Visual integration via theme parity makes the two systems feel like one product
- Co-located hosting keeps costs at zero while traffic is light; clean escalation path when it isn't
Negative / risks:
- Two systems to operate (Moodle + WordPress) versus one for plugin-based LMS
- Sysadmin burden: Moodle security patches, plugin compatibility, backups
- Theme parity requires ongoing maintenance — when
guildcommerce-themechanges, Boost Union CSS needs matching updates - SSO bridge is custom code in
guildcommerce-core-plugin; bugs there mean broken member experience - Two applications on one Cloudways environment means a Cloudways-level outage takes both down simultaneously (mitigated by Cloudways' managed redundancy)
Mitigations:
- Cloudways managed hosting handles patching, backups, and SSL automatically
- Boost Union CSS lives in the same repo as
guildcommerce-theme; theme PRs include LMS theme parity checks - SSO bridge gets unit tests + smoke tests in CI; well-defined OIDC contract
- Cloudways Autonomous handles resource scaling at the platform level, so co-deployment is operationally appropriate without a split trigger
When to revisit¶
- Member volume + course volume justifies a hosted LMS contract (e.g., Open LMS) for support and SLA reasons
- Regulatory or accreditation body requires Open Badge issuance, triggering Credly/Accredible reconsideration
- The Ganjier-brand license is amended to allow Ganjier-program content delivery, requiring license-aware course-publishing controls
- Cloudways tier change (downgrade to managed VPS) reintroduces fixed-capacity considerations
- A future credentialing program needs proctored exams, requiring Moodle Workplace or a proctoring service add-on
Implementation¶
| Step | Owner | Status |
|---|---|---|
Provision learn.ganjierguild.com subdomain |
Sysadmin | Pending |
| Add Moodle as a new application on existing Cloudways Autonomous environment | Sysadmin | Pending |
Install + configure Boost Union theme matching guildcommerce-theme |
Full-stack dev | Pending |
Install auth_oidc, mod_customcert, completion-webhook plugins |
Sysadmin | Pending |
Build lms-bridge module in guildcommerce-core-plugin |
Full-stack dev | Pending |
Build ce-ledger module in guildcommerce-core-plugin |
Full-stack dev | Pending |
| Build BuddyBoss profile "My Learning" tab | Full-stack dev | Pending |
| Define Year 1 Guild-original course roadmap | Education chair + founding board | Pending |
| Author first Guild-original course | Education chair | Pending |
| Update Form O matrix with course visibility rules | Operations Lead | Pending |
| Document operational workflows | Operations Lead | This commit (programs/learning/README.md) |
| Member-facing announcement | Communications chair | Pending |
| Verify Cloudways Autonomous monitoring + alerting covers both apps | Sysadmin | Pending |