This developer note documents the BricksMembers Connected Content runtime: cross-post relation storage, primary resolution, native Bricks Posts query filtering, connected dynamic tag projection, directed field synchronization, provider boundaries, extension points, and AI/MCP abilities.
Since version 1.4.0.
Scope and Non-Goals
Connected Content relates two eligible local WordPress posts under a configured type. It can project source fields live through Bricks, constrain native post loops to related posts, and optionally materialize selected source values into a target field.
- It does not replace WooCommerce, FluentCart, or SureCart product-to-level mapping. Commerce integrations remain the access-assignment owners.
- It does not register a new Bricks query type. It adds one control to native Posts queries.
- It does not infer arbitrary ACF relationship fields or scan structure metadata at runtime.
- It does not write remote commerce data or pricing, stock, checkout, subscription, variation, or payment state.
Runtime Owners
ConnectedContentFeatureRegistrarowns feature-local bootstrap, fail-closed runtime hook registration, active-module adapters, post-deletion cleanup, and builder/admin registration.ConnectedContentSettingsServiceexclusively ownsbrm_connected_content_settings: connection types, aliases, directed mappings, revision checks, graph validation, and target-owner conflict validation.ConnectedContentConnectionWriteServiceexclusively ownsbrm_content_connectionswrites and primary-selection invariants.ConnectedContentConnectionReadServiceowns bounded reads, current/top-level structure anchor resolution, primary selection, request memoization, and object-cache invalidation.ConnectedContentDynamicTagIntegrationparses aliases and expert syntax, resolves a primary related post, applies exposure policy, and delegates the inner tag to Bricks with the source post ID.ConnectedContentFieldSyncServiceowns save observation, ID-only job enqueueing, cursor backfills, endpoint resolution, identical-value no-ops, and recursion guards.ConnectedContentFieldWriteServiceowns the materialized-write adapter and delegates to WordPress, WooCommerce, ACF, orContentFieldValueService.
Bootstrap and Disable Contract
BootstrapCoordinator::boot_modules()callsConnectedContentFeatureRegistrar::boot().- The registrar always installs tag/query fail-closed adapters and post-deletion cleanup.
- When
ModuleRegistry::is_active( 'connected_content' )is false, saved tags render empty and saved connected queries return no posts. - When active, the registrar ensures schema and adds admin handlers, authenticated lookup AJAX, builder picker entries, save observers, and the internal queue handler.
Module disablement preserves definitions and relations. Full-data uninstall deletes the option, table, module flag, and schema flags.
Storage Contract
- Definitions:
brm_connected_content_settings - Relations:
{prefix}brm_content_connections - Schema flags:
brm_connected_content_tables_createdandbrm_connected_content_schema_version - Relation uniqueness: connection type plus Owner/Connected post IDs
- Nullable SHA-256 primary keys enforce at most one primary relation per endpoint, post, and connection type.
Anchor and Primary Resolution
resolve_connection_anchor_post_id() checks the current post first. If no relation exists, it calls StructureNavigationService::resolve_scope_post_id( ..., 'toplevel' ) once and checks that post. The reader does not walk arbitrary ancestors or scan _brm_parent_level_*.
One matching relation resolves without a primary marker. With multiple relations, all rows must place the context post on the same endpoint and one row must be marked primary for that endpoint. Ambiguous mixed-side or unpromoted sets resolve to zero.
Native Bricks Posts Query Contract
The builder control key is brmConnectedContentFilter. Its value is a configured connection-type key. ConnectedContentBricksPostQueryVarBuilder validates the module, type, schema, and resolved anchor, then adds only:
The control registrar attaches that key to native post loops on Section, Container, Block, Div, Accordion, Slider, and Posts elements. An omitted query.objectType is Bricks’ default Posts query and is handled like the explicit post value; explicitly non-post query types are not registered.
brmConnectedContentActive
brmConnectedContentType
brmConnectedContentAnchorId
bricks_force_run
ConnectedContentBricksPostQuerySqlFilter consumes those flags and adds two-direction indexed EXISTS constraints. Pagination, ordering, post type, and other native query behavior remain owned by Bricks and WordPress. An invalid saved state sets post__in to [0].
brm-community-link with linkDirection=show_content is intentionally outside the Connected Content module. It is a Community-owned nestable that exposes the authorized WordPress post already attached to the active Community Item or Reply through CommunityBricksAttachedTargetContextBuilder and CommunityBricksLinkedPostContext. It does not read brm_content_connections, and it must not be implemented through brmConnectedContentFilter or a second Community Area.
Dynamic Tag Contract
{brm_connected:alias_key}
{brm_connected:connection_type:endpoint:inner_bricks_tag}
Endpoint values are owner, connected, or other. The inner value must be an allowed post-scoped Bricks tag. WordPress post fields, featured images, ACF/custom fields, native Content Fields, and the allowlisted WooCommerce tag family are supported. Unsafe modifiers, nested brm_connected tags, action execution, and non-post-scoped families are rejected.
Expert tags always inherit source access. Aliases default to inherit; an explicitly public alias bypasses the source-post gate only for reviewed public marketing output. Native Content Fields still require their own public flag.
Field Sync Contract
A mapping identifies one connection type, a source endpoint/reference, a different target endpoint/reference, an enabled state, and the on_save trigger. The settings owner rejects endpoint self-writes, graph cycles, unavailable fields, protected metadata, and competing target owners.
- WordPress fields:
title,excerpt,content,slug,featured_image - ACF: an existing field key resolved through the ACF API
- BRM Content Fields: an existing field key delegated to
ContentFieldValueService - Safe meta: an explicit key and one of
text,textarea,rich_text,number,boolean,url, ormedia_id
save_post enqueues only relation ID, mapping ID, cursor, and reason. Values never enter the queue payload. Backfill jobs process 50 relation IDs at a time, mapping jobs allow three attempts, and identical normalized values are no-ops.
An enabled mapping delegates target-edit authority to source editors. Administrators must connect only source post types and fields whose editors are trusted to update the selected target.
Commerce Provider Boundaries
- WooCommerce: local
productpost fields route throughWC_Productsetters for name, description, short description, slug, and image ID. Pricing, inventory, variations, checkout, subscription, and payment state remain blocked. - FluentCart:
fc_productandfluent-productsparticipate as local posts through WordPress, ACF, Content Fields, or safe local metadata. - SureCart: local
sc_productposts may participate in relations and local-field projection. Remote SureCart cloud models are outside this workflow, and WordPress post-field writes tosc_productare not Field Sync targets.
Events and Filters
do_action(
'brm_connected_content_field_synced',
$connection_id,
$mapping_id,
$target_post_id
);
apply_filters(
'brm_connected_content_field_options',
$options,
$post_types
);
The successful-sync action intentionally omits the field value. Extensions adding field options are responsible for maintaining the same safe read/write and sanitization boundary.
Authenticated Admin Lookups
brm_connected_content_search_postsrequires the centralized admin nonce,CAP_MANAGE_CONNECTED_CONTENT, a request throttle, eligible post types, and object-leveledit_post. It returns at most 50 rows.brm_connected_content_field_optionsuses the same capability/nonce/throttle boundary and returns definitions only, never stored values or secrets.
AI/MCP Abilities
bricksmembers/connected-content-catalog-getbricksmembers/connected-content-connections-getbricksmembers/connected-content-settings-planbricksmembers/connected-content-connection-planbricksmembers/connected-content-sync-plan
Read abilities return definitions and relation metadata, not field values or secrets. Plans are dry-run-first. Approved commits delegate through AiConnectedContentCommitService to the canonical settings, relation, or sync owner.
Operational Guidance
- Prefer Dynamic Aliases over Field Sync when the value is only rendered in Bricks.
- Keep product-to-level mapping in the provider integration. Do not infer access from a content relation.
- Keep one canonical source for every synchronized field and avoid bidirectional ownership.
- Use the top-level course as the relation anchor when lesson templates need the same connected product.
- Start maintenance work from
the Connected Content feature map in the plugin repo.