BricksMembers uses a normalized storage model for user levels, post requirements, and direct completions, plus derived projection tables for structure and aggregate progress.
Core Runtime Model
- Canonical structure truth:
_brm_parent_level_*post meta - Derived structure projection:
brm_post_data - Canonical user levels:
brm_user_level_assignments - Canonical post requirements:
brm_post_level_requirements - Canonical direct completions:
brm_user_post_completions - Aggregate progress projection:
brm_user_progress
Drip runtime model: Global drip rules live in brm_global_drip_rules and are normalized before runtime. Rule targeting now supports structure, selected_posts, and post_type. Per-post drip behavior can be overridden via _brm_drip_override. Preserved unlock timestamps live in brm_user_unlocks, but computed drip status remains the canonical runtime access truth for conditions, filters, and frontend rendering.
Protected downloads capability model: the admin surface is gated by brm_manage_downloads, and the brm_download post type uses BRM-specific capabilities such as edit_brm_download and create_brm_downloads. Administrators receive those caps automatically so the downloads module does not mutate global WordPress capabilities.
Core API
$levels = brm_get_user_levels( $user_id );
$has_access = brm_can_user_access_content_now( $user_id, $post_id );
brm_add_user_level( $user_id, $level_id );
brm_set_post_levels( $post_id, [ 1, 2 ] );
brm_mark_content_completed( $user_id, $post_id );
$is_completed = brm_is_content_completed( $user_id, $post_id );
Developer Rules
- Use public
brm_*APIs for extension-facing reads and writes - Use canonical services directly inside plugin internals
- Do not treat
brm_user_dataas runtime truth in0.9.82+ - Do not write structure paths directly unless you are in the projection/rebuild layer
- Use request cache and batch loaders instead of ad-hoc repeated queries
- Normalize drip rules through the drip rules service instead of reading raw option arrays directly
Optional Modules
Progress, drip, downloads, quizzes and assessments, groups and team licenses, and submissions all build on the same core access and structure model. Check module activation before calling module-specific helpers.
Progress target reads such as {brm_progress:completed_item:last} belong to CompletedItemTargetReadService, with SQL delegated to ProgressTrackingReadService. The dynamic tag renderer is only the Bricks adapter; it does not own completion storage or structure scoping.