Goal
Bootstrap a sibling plugin only when:
- mam-main is installed and active
- mam-main is at the required version
- The customer is entitled to use this plugin
Background
mam-main exposes two filters for sibling-plugin gating:
mam_check_required_version— checks whether a plugin is at a sufficient versionmam_plugin_entitlement— checks the WPMAM entitlement record for a plugin slug
A well-behaved sibling plugin checks both before bootstrapping its hooks. A poorly-behaved one bootstraps unconditionally and produces fatal errors when mam-main isn’t loaded — or worse, runs on un-entitled customer sites.
Steps
1. Wrap your bootstrap in a plugins_loaded callback at priority 11
mam-main runs its register_*() chain on its own constructor (called early). By priority 11 on plugins_loaded, mam-main’s hooks are registered and its filters are answerable.
add_action( 'plugins_loaded', 'mam_my_plugin_bootstrap', 11 );
2. Check the required version
function mam_my_plugin_bootstrap() {
$required_version = '1.9.1';
$mam_version = apply_filters( 'mam_check_required_version', $required_version, 'MAM My Plugin' );
if ( version_compare( $mam_version, $required_version, '<' ) ) {
// mam-main is too old (or missing).
add_action( 'admin_notices', 'mam_my_plugin_required_version_notice' );
return;
}
// ... continue
}
The filter takes two args — the required version and a plugin label — and returns the installed mam-main version string (it also logs an admin alert when the installed version is below the requirement). Compare the returned version yourself with version_compare(); it does not return a boolean.
3. Check entitlement
function mam_my_plugin_bootstrap() {
// ...required version check...
$entitlement = apply_filters( 'mam_plugin_entitlement', null, 'mam-my-plugin' );
$state = is_array( $entitlement ) ? ( $entitlement['state'] ?? '' ) : '';
if ( 'blocked' === $state ) {
// Not purchased, or entitlement revoked — silently skip.
return;
}
if ( 'expired' === $state ) {
// Past expiry — show admin notice but don't bootstrap.
add_action( 'admin_notices', 'mam_my_plugin_expired_notice' );
return;
}
// state is 'entitled' or 'grace' → bootstrap functional code
}
The filter always returns an array with a state key — one of entitled, grace, blocked, or expired (plus reason, plugin_slug, and expires_at for grace/expired). It never returns a bare false, so gate on the state value, not on truthiness. Cache misses and unreachable WPMAM fail open (returned as entitled).
4. Bootstrap your plugin
function mam_my_plugin_bootstrap() {
// ...gate checks...
// OK to bootstrap.
new MAM_My_Plugin_Manager();
}
Common admin-notice patterns
function mam_my_plugin_required_version_notice() {
echo '<div class="notice notice-warning"><p>';
echo 'MAM My Plugin requires MAM Main version 1.9.1 or later.';
echo '</p></div>';
}
function mam_my_plugin_expired_notice() {
echo '<div class="notice notice-error"><p>';
echo 'MAM My Plugin entitlement has expired. Contact support to renew.';
echo '</p></div>';
}
Show notices only on admin pages where they’re useful — guard with is_admin() and screen checks if needed.
Caching the gate decision
The entitlement filter is cached on the mam_entitlement_manager side, so calling it once on bootstrap is fine. Don’t re-check on every request:
// Good — bootstrap-time check, cached for the session
function mam_my_plugin_bootstrap() {
$entitlement = apply_filters( 'mam_plugin_entitlement', null, 'mam-my-plugin' );
if ( 'blocked' === ( $entitlement['state'] ?? '' ) ) return;
// ...
}
// Bad — checking on every request
add_filter( 'some_hook', function ( $value ) {
$entitlement = apply_filters( 'mam_plugin_entitlement', null, 'mam-my-plugin' ); // ← redundant
if ( 'blocked' === ( $entitlement['state'] ?? '' ) ) return $value;
// ...
} );
What “entitled” means
The entitlement record is per-customer-site and per-plugin. A site might have:
- Some plugins entitled, others not
- A plugin entitled at one tier (basic) but not another (premium)
- An entitlement that expires and renews via WPMAM
- An entitlement that’s been blocked by support
Your plugin should respect the record’s state field (entitled, grace, blocked, expired) and adapt accordingly.
Gotchas
- Priority 11 on
plugins_loaded. Not 10 — at priority 10, mam-main’sregister_*()chain hasn’t necessarily completed. - Don’t bootstrap on file include. Wait for
plugins_loadedso mam-main is loaded. - Entitlement can change at runtime. A plugin that bootstraps once per request and caches the gate decision in PHP memory will not pick up a same-request entitlement change. Acceptable for most cases; if your plugin needs to react to revocation, use a longer-running mechanism (cron + invalidation).
- WPMAM unreachability can produce stale entitlement reads. The graceful-degradation hook (
mam_account_code_verify_fallback-style) typically defaults to “still entitled” during planned outages — confirm behavior with WPMAM ops. - Don’t try to “auto-recover” from blocked entitlement. A blocked entitlement means contact support.
Related articles
- Extending mam-main: developer guide
- Integration: Account code and enrollment server
- Hook: mam_plugin_entitlement
- Frozen public contracts reference
Metadata
| Field | Value |
|---|---|
| Article type | Recipe (Developer) |
| Plugin slug | mam-main |
| Applies to plugin version | 2.1.11+ |
| Category | Extending MAM Suite |
| Audience | PHP developer |
| Estimated time | 15 minutes |
| Last verified | 2026-05-02 |
