This developer note documents the paid BricksMembers compatibility bridge for sites upgrading from Members for Bricks Builder. The bridge keeps the Free storage contract readable, deactivates the Free plugin when both are active, enables paid payment modules when Free Stripe EasySync data exists, and preserves the old EasySync webhook route.
Runtime Owners
BaselMedia\BricksMembers\FreeEdition\FreeEditionUpgradeServiceowns paid-side Free contract detection, Free plugin deactivation, payment-module enablement, and admin notices.BaselMedia\BricksMembers\FreeEdition\EasySyncWebhookAliasControllerowns the paid compatibility route at/wp-json/bricksmembers/v1/stripe-easysync/webhook.BaselMedia\BricksMembers\Modules\Payments\PaymentsWebhookControllerremains the canonical paid Stripe webhook processor. The EasySync alias delegates to it instead of duplicating Stripe signature or billing mutation logic.
Free Contract Detection
The paid runtime treats the install as Free-compatible when any of these markers exist:
brm_free_edition_installedbrm_free_storage_contract_versionbrm_stripe_easy_enabled
Do not call Free plugin classes from the paid plugin. The paid bridge reads the documented options and shared BRM tables only.
Admin Upgrade Flow
Plugin::register_hooks()bootsFreeEditionUpgradeService.- On
admin_init, the service deactivatesmembers-for-bricks-builder/members-for-bricks-builder.phpwhen the current user can activate plugins and both plugins are active. - If
brm_stripe_easy_enabledis true, the service enablesbrm_enable_paymentsandbrm_enable_payments_stripe. - The service writes
brm_free_contract_imported_atonce and stores a one-time notice inbrm_free_upgrade_bridge_notice.
Compatibility REST Route
The route POST /wp-json/bricksmembers/v1/stripe-easysync/webhook is registered only when a Free contract marker exists. Its REST permission callback is public for the same reason native provider webhooks are public: provider signature validation belongs inside the delegated Stripe webhook controller.
If paid Payments or paid Stripe is not active, the alias returns 503 with an explanatory message. Otherwise it passes the request to PaymentsWebhookController::handle_webhook_stripe().
Storage Contract
The bridge relies on the Free package using paid-compatible storage for core membership data:
brm_levelsbrm_user_level_assignmentsbrm_post_level_requirementsbrm_post_databrm_payments_settings.providers.stripebrm_payments_offers
Free-only Stripe ledgers, such as brm_free_stripe_entitlements and brm_free_stripe_events, remain compatibility data unless a later migration explicitly imports them into paid billing rows.
Implementation Rules
- Do not duplicate Stripe signature validation in the alias controller.
- Do not add a second billing mutation path for Free events. Delegate to the paid Payments webhook controller.
- Do not depend on Free PHP classes being loaded after paid BricksMembers is active.
- Keep user-facing upgrade notices one-time and dismissible. The bridge should not create a permanent dashboard warning after the contract has been imported.