The Protected Downloads module combines a dedicated download post type, access-checked delivery, optional provider-backed remote files, and assigned-download reads for Bricks layouts. The canonical runtime owner is src/Modules/Downloads/DownloadRuntime.php. Since version 1.1.12, assigned-download reads include both post-level and structure-level assignment scopes.
Module Gate and Entry Points
- Module flag:
brm_enable_protected_downloads - Bootstrap path:
src/Bootstrap/BootstrapCoordinator.php→DownloadRuntime::boot() - Admin page:
admin.php?page=brm-downloads - Bricks element:
src/Elements/ProtectedDownloadElement.php - Assignment owner:
src/Modules/Downloads/DownloadAssignmentService.php
Core Runtime Responsibilities
- register the
brm_downloadpost type - add rewrite rules and handle secure download requests
- boot provider support and the remote file browser
- register meta boxes and save download metadata
- serve either local protected files or signed remote URLs
- create the optional download logs table
Provider Architecture
Remote providers register through src/Modules/Downloads/Providers/ProviderRegistry.php. The current provider set includes Local, S3, Bunny, and GCS adapters. For remote downloads, DownloadRuntime asks the active provider for a short-lived signed URL and redirects the browser there after access checks pass.
Assigned Downloads
DownloadAssignmentService owns the relation between content posts, content structures, and download posts. Post assignments remain repeated post meta under _brm_assigned_download_id. Since version 1.1.12, structure assignments are stored in per-structure options named brm_structure_assigned_downloads_{structure_id} with autoload disabled. The structure interface AJAX layer validates the editor request and delegates persistence to this service; it does not own download assignment storage.
The Assignable Post Types setting is part of the same assignment owner. The settings UI posts the complete checkbox map as brm_download_assignment_post_types through brm_save_download_settings; DownloadsAdminHandlers accepts either normal form arrays or JSON AJAX payloads and delegates persistence to DownloadAssignmentService::save_supported_post_type_map(). The stored option is brm_download_assignment_post_types with autoload disabled.
Render adapters use assignment reads in three places: ProtectedDownloadElement resolves selected/manual, current post, specific post, current structure, and specific structure sources; native Bricks Posts query loops use the assigned-download query controls for brm_download; and DownloadsDynamicTags resolves scalar assignment modifiers such as {brm_download:url:post} and {brm_download:filename:structure=course_slug}.
Dynamic Tags and Assistant Metadata
DownloadsDynamicTags owns protected-download dynamic tag rendering. Download tags cover the secure URL/default output, explicit :url, link HTML, filename, formatted size, file type, image outputs, fixed download IDs, and since version 1.1.12, post/structure assignment modifiers. DynamicTagAssistantCatalog, DynamicTagAssistantTagGenerator, and DynamicTagAssistantTagDescriber describe and generate those tags for the Bricks Dynamic Tag Assistant, but runtime rendering stays in DownloadsDynamicTags.
Secure Delivery Flow
- resolve the requested download
- require a logged-in user for protected delivery
- check access through the BRM download access helper
- log the download when logging is enabled
- serve the local file or redirect to a provider-signed URL
Admin Surfaces
src/Admin/Pages/Routes/DownloadsPage.phpsrc/Admin/DownloadsAdmin.phpsrc/Admin/DownloadsAdminHandlers.php
These classes own the admin UI transport. They do not become alternate owners for runtime access rules or provider delivery.
The current downloads page uses assets/admin/js/downloads.js. The old duplicate page renderer and old downloads page script were removed when the final brm-downloads route became the only downloads admin surface, so there is no separate legacy settings script to keep in sync.
Edit Guidance
- Start in
DownloadRuntimefor runtime delivery, CPT wiring, or provider boot. - Start in
DownloadAssignmentServicefor assignment persistence and current-post reads. - Start in the provider adapter when the change is provider-specific.