This reference documents the current Content Bank implementation in BricksMembers: module boot, storage model, structure-editor integration, Bricks behavior, dynamic tags, cache invalidation, and the public helpers exposed to other runtime code.
Overview
The Content Bank is an opt-in BRM module that introduces reusable source posts and structure-specific proxy posts. A proxy is still a real WordPress post, but it stores a source reference and participates in shared-content resolution.
- Admin surface —
BricksMembers → Content BankviaContentBankPage - Editor surface — post meta box for source/proxy management via
ContentBankRuntime - Structure surface — staged
Insert from Bankmodal plus proxy creation during structure commit - Bricks surface — source-first builder redirects, dynamic tags, and Bricks conditions
Module Boot Path
src/Core/ModuleRegistry.phpmapscontent_banktobrm_enable_content_bank.src/Utilities/ModuleConfig.phpexposes the module toggle in the normalized module config.src/Bootstrap/BootstrapCoordinator.phpbootsContentBankRuntimeand conditionally registersContentBankAjaxduring AJAX requests when the module is active.src/Admin/Menu/AdminMenuRegistrar.phpadds the dedicated Content Bank admin page when enabled.
The implementation is intentionally module-gated so the feature adds no runtime hooks when disabled.
Canonical Storage
The Content Bank uses standard WordPress posts plus BRM meta/taxonomy keys. There is no custom Content Bank table.
_brm_bank_item— marks a source post_brm_bank_source_id— links a proxy to its source_brm_bank_blocked_fields— meta keys that should stay empty on a proxy instead of inheriting_brm_bank_title_customized— legacy cleanup/protection key from the previous copied-field model_brm_bank_content_customized,_brm_bank_excerpt_customized— legacy compatibility markers for explicit body/excerpt overrides on older proxiesbrm_collectiontaxonomy — organizes source items in the library
Core field behavior is intentionally hybrid:
- Title and slug stay local on the proxy and are not resynced from the source after proxy creation.
- Body and excerpt delegate live from source to proxy when the proxy value is empty; adding a local value makes that field local, and clearing it returns the field to source fallback.
- Meta, including featured image and custom fields, delegates live from source to proxy until the proxy stores a non-empty local value or blocks that key. Empty local meta values are treated as missing.
- Content Fields scalar values are native postmeta and therefore follow the same source/proxy fallback path. Definition ownership, sanitization, and required-field validation remain in the Content Fields module.
- Source saves invalidate Content Bank runtime caches through
MutationContract::bank_source_updated()but do not write shared content into proxy post rows.
Core Service Layer
The main runtime lives in src/Modules/ContentBank/ContentBankService.php.
is_bank_item(),is_proxy(),get_source_id(),get_source_post()— identity and lookup helperscreate_proxy()— creates a real proxy post, stores its source link, and applies optional local levels/taxonomy argsdetach_proxy(),remove_proxy()— proxy lifecycle actionsget_delegated_meta()— central meta-resolution hook targetget_delegated_core_field(),handle_source_saved(),handle_proxy_saved()— resolve empty proxy body/excerpt fields from the source, invalidate runtime caches after source saves without mutating proxy rows, and remember explicit body/excerpt overrides when the proxy itself is editedbrowse_bank_items(),save_collection(),import_bank_data(),export_bank_data()— admin/library flows
Request Registry and Batch Loading
Content Bank keeps request-local state in the RequestRegistry and primes loop data through BatchLoader integration.
bank_proxy— resolved proxy → source IDsbank_local_meta— local meta keys with non-empty content on a proxybank_blocked— blocked inherited meta keys per proxysrc/Batch/BatchBankLoader.phpprimes source lookups during batched post loads
This keeps proxy/source resolution cheap in query-loop heavy templates.
Structure Editor Integration
The structure integration deliberately uses the existing staged-edit flow instead of inventing an immediate-write side channel.
assets/admin/js/content-bank-structures.jsopens the modal, browses source items via AJAX, and stages a create payload withbank_source_id.src/Admin/StructureAdminController.phplocalizes the Content Bank strings and library URL into the structure admin runtime.src/Structures/Ajax/StructureCommitAjax.phpdetectsbank_source_idduring staged creates and callsContentBankService::create_proxy()instead ofwp_insert_post().
The result is consistent with the rest of the structure editor: proxy insertion remains part of the same staged save/commit lifecycle.
Admin Page and Request Handling
ContentBankPage renders the dedicated admin screen. ContentBankRuntime handles the corresponding admin request flows:
- collection create/update/delete
- source library export
- JSON import of source items
- proxy detach flows from the post editor
The current implementation uses BRM security wrappers, nonce verification, and capability checks around those paths. Import handling accepts JSON source-library files only. Export uses a normal download response with a sanitized filename.
Bricks Integration
Bricks integration is intentionally source-first.
filter_builder_edit_link()redirects proxy builder entry points to the source builder URLmaybe_redirect_proxy_bricks_builder()handles front-end proxy builder requests and redirects to the source unless the explicit proxy-edit flag is presentrender_proxy_bricks_notice()explains whether the user is editing the shared source or localizing a proxy
Important implementation detail: BRM does not intercept Bricks saves and rewrite them back onto the source. If a proxy is edited directly in Bricks and saved, that proxy localizes its own Bricks meta and stops inheriting the shared layout for those keys.
Dynamic Tags and Conditions
Content Bank tags are registered through BricksDynamicTagListComposer and wired into Bricks rendering through UtilityBootstrap and the dynamic tag integration path.
{brm_bank_is_proxy}{brm_bank_source_title}{brm_bank_source_id}{brm_bank_usage_count}{brm_bank_collections}
The conditions layer is registered through the Bricks condition registrar path and evaluated by BricksConditionsRegistrar.
AJAX Endpoints
ContentBankAjax currently registers two admin AJAX handlers:
wp_ajax_brm_bank_browse— browse source items for the structure modalwp_ajax_brm_bank_get_usage— retrieve proxy usage for a given source
Both use the normal BRM AJAX nonce. Browsing validates the requested post type and restricts results to items editable by the current user.
Public Runtime Helpers
brm-public-api.php currently exposes the following Content Bank wrappers:
brm_is_bank_item( $post_id )brm_is_bank_proxy( $post_id )brm_bank_get_source_id( $post_id )brm_bank_get_usage_count( $post_id )
These helpers are safe to call from theme/plugin code because they return fallback values when the module is disabled.
Mutation Contract and Cache Invalidation
MutationContract owns the Content Bank cache invalidation rules.
bank_proxy_created()bank_proxy_removed()bank_source_updated()
These methods invalidate the brm_bank cache group and clear affected proxy/source request-runtime state.
Implementation Gotchas
- Do not treat proxies as virtual records. They are normal posts and should continue to fit normal BRM structure/access/progress flows.
- Do not reintroduce source-save writes into proxy rows. Proxies should read shared body, excerpt, and meta values dynamically when their local value is empty.
- Do not treat empty proxy meta as a local override. Empty local values are intentionally equivalent to missing values.
- Do not add an immediate-write side path for structure insertion while the staged editor exists. Proxy creation should stay in the staged commit pipeline.
- Do not assume editing a proxy in Bricks updates the source. Direct proxy saves localize that proxy.