Summary
mam-main’s settings are scoped at three levels: per-button, per-role, and global. The cascade resolves in that order — the most specific scope wins.
Per-button settings
Per-button settings live inside the button’s record in local-app-button-array*. There’s no normalized schema — the button is a serialized array, and per-button settings are keys on that array.
A typical button blob:
array(
'id' => 'btn_42',
'title' => 'Edit listing',
'content_type' => 'open_form',
'icon' => 'black_edit',
// per-button settings:
'visible' => 'on',
'require_login' => 'yes',
'pass_user_id' => 'yes',
'style_bg_color' => '#1A73E8',
'style_fg_color' => '#FFFFFF',
)
The content class’s app_settings() declarations include environment => 'per-button' for fields stored here.
⚠️ Per-button settings are blob-shaped. Readers must defensively handle missing keys. The Content_Class_Interface refactor (tracked) will introduce a schema; for now treat any read as ?? $default.
Per-role settings
Per-role settings live in role-specific options. Convention: <global-key>_<role>.
| Global key | Per-role variant |
|---|---|
tsl-setting-geofilter_radius |
tsl-setting-geofilter_radius_subscriber, ..._admin, ..._anonymous, etc. |
mam-button-array |
local-app-button-array_subscriber, etc. |
mam-layout-settings |
per-role layout variants |
The data manager handles the per-role naming; subscribers don’t construct option keys directly.
Global settings
Site-wide values stored in their canonical option key (no role suffix).
The cascade
Reading via mam_app_settings_get_setting:
1. If a button context is supplied: per-button blob value (if set)
2. Per-role override (if set for $role)
3. Global value (if set)
4. The supplied $default
The first hit wins.
Reading examples
Read a per-role value with global fallback:
$radius = apply_filters(
'mam_app_settings_get_setting',
25, // default
'subscriber', // role
'general-settings', // category
'tsl-setting-geofilter_radius' // key
);
// → if subscriber-specific value exists, returns it
// → else if global value exists, returns it
// → else returns 25
Read a per-button value (called from the button-rendering loop):
The button-rendering loop reads per-button settings directly from the button blob; it doesn’t call mam_app_settings_get_setting for those. The filter is for when an external caller needs a per-button value without having the blob in hand.
Writing examples
Write a per-role value:
apply_filters(
'mam_app_settings_set_setting',
'new value',
'subscriber', // role-scoped
'general-settings',
'tsl-setting-geofilter_radius'
);
Write a global value:
apply_filters(
'mam_app_settings_set_setting',
'site-wide value',
'', // empty role = global
'general-settings',
'tsl-setting-geofilter_radius'
);
The data manager interprets the empty role as the global scope.
Roles in mam-main
mam-main recognizes the standard WP roles plus its own:
anonymous— unauthenticated visitorsubscriber,contributor,author,editor,administrator— WP standardcloning— admin previewing as another role (MAM_Current_Request->is_cloning())- Sibling-plugin custom roles (e.g.,
gd_listing_ownerfrom mam-geodirectory)
The role string is whatever MAM_Current_Request->user_role() returns.
Gotchas
- Per-button settings are blob-shaped, no schema. Always
?? $default. - Per-role option-key construction is the data manager’s job. Constructing
'foo_' . $roleyourself bypasses the cascade. - Cloning admins see settings for the role they’re cloning, not their actual admin role. Check
is_cloning()if you need the underlying admin context. - Hot path. Don’t add expensive subscribers to the cascade.
- The cascade is in the data manager, not implemented by chained filter subscribers. Don’t try to re-implement.
Related articles
- Settings cascade overview
- Button array storage
- Frozen public contracts reference
- Hook: mam_app_settings_get_setting
- Hook: mam_app_settings_set_setting
Metadata
| Field | Value |
|---|---|
| Article type | Plugin Overview |
| Plugin slug | mam-main |
| Applies to plugin version | 2.1.11+ |
| Category | App Settings Reference |
| Audience | PHP developer |
| Last verified | 2026-05-02 |
