Since version 1.3.0: BricksMembers includes a SCORM Cloud-backed runtime for package import, package-to-post assignment, learner launch, provider sync, Cloud postbacks, and completion bridging into the canonical progress system.
This developer post documents the SCORM subsystem as implemented in BricksMembers. The module is intentionally provider-scoped: SCORM Cloud is the only exposed runtime provider, while local manifest parsing is used only for validation and metadata extraction before upload.
Ownership summary
| Concern | Owner |
|---|---|
| Module bootstrap | BaselMedia\BricksMembers\Modules\Scorm\ScormFeatureRegistrar |
| Schema installation | BaselMedia\BricksMembers\Modules\Scorm\ScormSchemaService |
| Package, SCO, assignment, registration, runtime, and event rows | BaselMedia\BricksMembers\Modules\Scorm\ScormRepository |
| Settings and secret-preserving normalization | BaselMedia\BricksMembers\Modules\Scorm\ScormSettingsService |
| SCORM ZIP validation and import orchestration | BaselMedia\BricksMembers\Modules\Scorm\ScormPackageImportService |
| Manifest parsing | BaselMedia\BricksMembers\Modules\Scorm\ScormManifestParser |
| SCORM Cloud API calls | BaselMedia\BricksMembers\Modules\Scorm\ScormCloudApiClient |
| SCORM Cloud provider behavior | BaselMedia\BricksMembers\Modules\Scorm\ScormCloudProvider |
| Registration, launch, sync, and snapshots | BaselMedia\BricksMembers\Modules\Scorm\ScormRegistrationService |
| Completion bridge | BaselMedia\BricksMembers\Modules\Scorm\ScormProgressBridgeService |
| Admin-post transport | BaselMedia\BricksMembers\Modules\Scorm\ScormAdminActionHandler |
| REST transport | BaselMedia\BricksMembers\Modules\Scorm\ScormRestController |
| Bricks element adapter | BRM_Element_Scorm_Player |
The canonical write owner for SCORM rows is ScormRepository. Transport adapters must validate input and delegate. SCORM completion must go through ScormProgressBridgeService and ProgressCompletionService; SCORM code must not write progress tables directly.
Bootstrap path
ModuleRegistryreadsbrm_enable_scorm.ScormFeatureRegistrar::boot()returns early when the module is inactive.- When active, the registrar installs additive schema through
ScormSchemaService. - Admin-post actions, REST routes, cron hooks, and the Bricks element delegate to SCORM services.
- Recurring cron hooks sync recent Cloud registrations and purge old event rows.
The feature map for ownership and routing is docs/feature-maps/scorm.md. Update it whenever entry points, write owners, provider boundaries, storage, or completion flow changes.
Storage contract
The SCORM schema is additive and versioned by ScormSchemaService. It creates the following tables when the module is active:
wp_brm_scorm_packageswp_brm_scorm_scoswp_brm_scorm_post_assignmentswp_brm_scorm_registrationswp_brm_scorm_runtime_valueswp_brm_scorm_events
Settings live in brm_scorm_settings. SCORM Cloud secret and postback secret values live behind SecretOptionService using brm_scorm_cloud_secret_key and brm_scorm_cloud_postback_secret.
Admin-post actions
| Action | Handler | Behavior |
|---|---|---|
brm_save_scorm_settings | handle_save_settings() | Saves provider defaults, Cloud API settings, launch TTL, diagnostics, and optional postback-secret rotation. |
brm_import_scorm_package | handle_import() | Validates the uploaded ZIP, parses the manifest, creates package metadata, and uploads to SCORM Cloud. |
brm_assign_scorm_package | handle_assign() | Connects a package UUID to a target post with completion policy, optional score, and launch mode. |
brm_sync_scorm_import | handle_sync_import() | Refreshes SCORM Cloud import status for a package with an import job ID. |
All admin-post actions require RoleCapabilityRegistry::CAP_MANAGE_SCORM and a matching nonce. They redirect back to the SCORM admin surface with a status or error code.
REST API
| Route | Method | Permission | Behavior |
|---|---|---|---|
/wp-json/bricksmembers/v1/scorm/packages | GET | SCORM admin capability | Lists packages for admin UI/API consumers. |
/wp-json/bricksmembers/v1/scorm/import | POST | SCORM admin capability | Imports a package from REST file params. |
/wp-json/bricksmembers/v1/scorm/launch | POST | Logged-in user plus rate limit; content access checked in callback | Creates or reuses a learner registration and returns a SCORM Cloud launch link. |
/wp-json/bricksmembers/v1/scorm/sync/{provider_registration_id} | POST | Registration owner or SCORM admin plus rate limit | Syncs provider status and applies completion bridge if eligible. |
/wp-json/bricksmembers/v1/scorm/cloud/postback | POST | Rate limit plus postback secret inside callback | Receives SCORM Cloud postbacks and syncs the referenced registration. |
The Cloud postback route is public at the REST permission layer because SCORM Cloud cannot send a WordPress nonce. It still authenticates with the configured secret before it mutates provider registration state.
Launch and sync flow
- The
brm-scorm-playerBricks element posts the current post ID to/scorm/launch. ScormRestController::launch()requires a logged-in user and checksread_post.- Non-admin users also pass through
ContentAccessGateService::can_user_access_content_now(). ScormRegistrationService::build_launch_for_post()reads the current post assignment, creates or reuses a registration, and asks the provider for a launch URL.- The frontend opens the launch URL embedded or in a new window, depending on the assignment or element override.
- SCORM Cloud postbacks or explicit sync requests call
ScormRegistrationService::sync_provider_registration(). - The sync stores the provider snapshot and asks
ScormProgressBridgeServicewhether BricksMembers progress should be completed.
Completion bridge
ScormProgressBridgeService evaluates the assignment completion policy against the synced registration snapshot. Supported policies are completed, passed, complete_or_passed, complete_and_passed, and score_threshold.
When the policy passes, the bridge calls ProgressCompletionService with trigger metadata that identifies SCORM as the source. This preserves the normal progress contract for downstream dashboards, automations, and structure progress.
Bricks element contract
BRM_Element_Scorm_Player registers the brm-scorm-player element. The element renders a launch shell only. It does not store package IDs, provider launch URLs, or progress data.
postId: optional post context override.launchMode: assignment default, embedded iframe, or new window.buttonText: visible launch label.button_style,button_size,acss_button_style, andacss_button_size: shared checkout/button style controls reused for the launch button.
The element enqueues assets/js/scorm-player.js and localizes the REST URL, REST nonce, and UI strings. User-facing JavaScript strings must continue to come from localized PHP data.
Security model
- SCORM ZIP uploads are untrusted and must go through
ScormPackageImportService. - ZIP import validates file type, byte limits, entry count, unsafe paths, manifest size, manifest XML, and launchable SCO presence.
- Admin mutation routes require
CAP_MANAGE_SCORMplus dedicated nonces. - Launch requires a logged-in user, post read permission, and active BricksMembers content access for non-admin users.
- Launch, sync, and postback routes use explicit
RateLimitingaction buckets. - Cloud postbacks require the configured postback secret and reject oversized payloads.
- Provider credentials and postback secrets are stored with
SecretOptionService.
Provider boundary
SCORM Cloud integration is isolated in ScormCloudApiClient and ScormCloudProvider. Do not add provider-specific HTTP calls to controllers, elements, cron callbacks, or repositories.
Do not expose a local SCORM runtime option unless the implementation includes a real runtime adapter, secure local asset serving, CMI persistence, attempt/resume behavior, and browser compatibility coverage.
Testing guidance
SCORM changes should be covered at the cheapest layer that can fail the regression. Unit coverage should focus on manifest parsing, upload rejection, settings normalization, repository writes, launch permission, postback authentication, sync behavior, and completion policy mapping. Browser or WordPress-admin smoke coverage is appropriate when changing the SCORM admin page or Bricks element behavior.
At minimum, run targeted PHPUnit coverage for the changed SCORM owner, PHPCS for changed PHP files, PHPStan, security QA for REST/postback changes, and release QA when the change affects package behavior or public release docs.
Edit guidance
- Start in
ScormSettingsServicefor credentials, defaults, launch TTL, retention, and secret rotation. - Start in
ScormPackageImportServicefor upload validation and package import orchestration. - Start in
ScormCloudApiClientorScormCloudProviderfor provider transport changes. - Start in
ScormRegistrationServicefor launch, registration, sync, and provider snapshots. - Start in
ScormProgressBridgeServicefor completion-policy behavior. - Start in
ScormRestControllerorScormAdminActionHandleronly for transport validation and response behavior. - Update
docs/feature-maps/scorm.md,docs/modules/scorm.md, and the user/developer posts when ownership, routes, storage, security, or launch/completion behavior changes.