Goal
You’ve installed a feature plugin — say mam-geodirectory, mam-chat-manager, or mam-special-offers — but its content (a listing screen, a chat tab, an offers carousel) isn’t showing up in the app. This how-to walks you through the most common causes in order, cheapest to check first, so you can find the break without guessing.
This diagnostic order works for any MAM Suite sibling plugin, because they all reach the app the same way: they bootstrap behind an entitlement gate, then add their data to the phone-data response through the mam_get_phone_data_before_send filter.
Background: how a sibling plugin’s content reaches the app
Every cold app launch calls the local_app_get_phone_data AJAX action (modern alias mam_get_phone_data), which runs MAM_Phone_Data_Pipeline. During the pipeline’s content phase, mam-main fires the mam_get_phone_data_before_send filter — and roughly 70 sibling plugins subscribe to it, each adding its own section to the response array.
For a plugin’s content to appear, all four of these have to be true:
- The plugin is entitled and active — it actually bootstrapped on this site.
- Its subscriber is registered at the right priority so it runs at the right point in the pipeline and isn’t overwritten.
- The current user’s role isn’t gating the content out.
- The cursor cache isn’t suppressing the section as “unchanged.”
The steps below walk through each one.
Prerequisites
- Admin access to the WordPress site (Mobile App Manager).
- The ability to reproduce the missing content in the Previewer or on a device.
- For the developer-oriented steps: access to the site’s PHP error log and the plugin source under the MAM Suite repo.
- Note which role you’re testing as. Anonymous (logged-out) and a signed-in subscriber can see very different screens.
Steps
1. Confirm the plugin is active and entitled
A sibling plugin only bootstraps when mam-main is active, mam-main is at the required version, and the customer site is entitled to that plugin. Miss any one of those and the plugin does nothing — silently, with no error and no content.
- In Plugins, confirm the feature plugin and MAM Main are both active.
- Confirm mam-main is recent enough for the feature plugin. A feature plugin checks
mam_check_required_versionagainst mam-main on bootstrap; if mam-main is too old, well-behaved plugins show an admin notice and stop. - Confirm the entitlement for this plugin. Entitlement is per-site and per-plugin, resolved through the
mam_plugin_entitlementfilter (backed by the WPMAM software-manager). A site can have some plugins entitled and others not, and an entitlement can beexpiredorblocked.
If the plugin isn’t entitled, you’ve found your answer — content won’t appear until the entitlement is in place. If you believe the site should be entitled and isn’t, contact support / WPMAM ops. A blocked entitlement is intentional rather than a bug, so that’s your cue to contact support too, not to look for a workaround.
Developer note: the gate runs on
plugins_loadedat the default priority 10, after mam-main has bootstrapped — mam-main inits earlier, atplugins_loadedpriority 2, and runs itsregister_*()chain there. A plugin that bootstraps too early, or that doesn’t gate at all, can either fatal-error or run on an un-entitled site — both worth ruling out if you maintain the plugin.
2. Verify the content is configured in the builder
Being entitled makes the plugin able to contribute — it doesn’t put anything on a screen by itself. Most feature plugins surface as a content class (a button type) or a tab-bar item that you still have to add.
- In Mobile App Manager → App Setup (Buttons / Tab Bar / Left Menu), confirm there is actually a button or tab of the feature plugin’s type placed on a screen.
- Open the per-button settings and confirm the relevant ID / source is filled in (for example a geodirectory listing type, or the offers source). A button placed but left unconfigured commonly renders nothing.
- Confirm
visibleis on for that button.
If nothing of the feature plugin’s type exists in the builder yet, add and configure one, then test again.
3. Re-test as the affected role
MAM Suite resolves most settings — and a lot of visibility — per role. The content you’re missing might be showing up fine for one role while another role has it gated out.
- Reproduce as the exact role that’s missing the content. Anonymous vs. a signed-in subscriber is the most common split — a screen that requires login shows nothing to anonymous users.
- Check the button’s
require_loginsetting. A login-gated button is correctly invisible to anonymous users. - Per-role settings live in role-specific options and resolve through the settings cascade (per-button → per-role → global → default). A per-role override can hide or empty out content that exists globally.
- Tab-bar buttons can be hidden per item / per user via the
mam_main_skip_tab_bar_buttonfilter (it returns[]to hide). If a feature plugin or a customization gates the button this way, it will be absent for some users and present for others.
Tip: when you “clone” another role in the Previewer, you’re seeing that role’s settings, not your own admin settings — that’s expected. Just make sure you’ve cloned the role you actually meant to test.
4. Rule out the cursor cache
The phone-data response is delta-cached per user via a cursor. A subscriber that supports the cursor can return null for its section to signal “nothing changed since your last fetch,” and the app keeps what it already had. If the underlying data changed but the section’s change-timestamp wasn’t bumped, the app can keep showing stale (or empty) content.
- Force a full rebuild — clear the app’s local cache (reinstall it, or use the app’s reset feature), or open the Previewer fresh, which bypasses the cursor for cloning admins.
- If the content appears on a forced full rebuild but not on a normal refresh, the cause is cache invalidation, not the content itself.
Developer note: when you mutate the data behind a section, bump that section’s change-timestamp option so the cursor comparison invalidates the per-user cache. Don’t re-implement the cursor mechanism; use
JSON_Cursor_Manager::get_cursor()and the section-levelnullsignal.
5. Check the subscriber actually runs (developer)
If entitlement, configuration, role, and cache all check out clean, the next thing to confirm is whether the plugin’s mam_get_phone_data_before_send subscriber is registered and actually producing output.
- Confirm the plugin registers the filter at all. If the bootstrap in step 1 returned early (un-entitled, version mismatch), the filter was never added.
- Inspect the response: capture the JSON from
local_app_get_phone_dataand look for the plugin’s top-level key. If the key is absent, the subscriber didn’t run or returned early. If the key is present but empty/null, the subscriber ran but produced no data (often a role or data-source issue — back to step 2 or 3). - If the plugin emits a tracer marker (
do_action('add_to_tracer', '...')), use the debug/tracer handler to confirm the section was built.
6. Check hook priority and last-writer-wins (developer)
The filter runs many subscribers in priority order, and they share one $data_array. Two problems show up here:
- Wrong priority. The default cohort for content providers is priority 10. Late enrichments run at 99–100,
home_catsinjection is reserved at 1000, and use-case total overrides run at 9999+. If a subscriber needs data another subscriber produced, it must run after it. A subscriber registered too early may build against data that isn’t there yet. - Overwritten key. If another subscriber (often a higher-priority use-case override) writes the same top-level key, last writer wins and your content is clobbered. Confirm the plugin owns a unique key and that no use-case override at 9999+ is replacing it. This is exactly how use-case overrides are designed to replace
main_button_arrayorhome_catswholesale — verify that’s not happening unintentionally on this site.
Never register a subscriber at priority 1000 — that’s reserved for home_cats — and don’t overwrite keys your plugin doesn’t own.
If content still doesn’t appear
If the JSON has the plugin’s data sitting there correctly but the app still shows nothing, the break has moved to the mobile client side: the client may not recognize the content type token the plugin emits. Registering something on the server doesn’t make a button render by itself — the mobile client also has to know that type. Confirm the app version supports the feature, then escalate to mobile-client support with the captured JSON.
Related
- Hook: mam_get_phone_data_before_send — the primary mobile-API extension point and its priority conventions
- Hook: mam_plugin_entitlement — per-plugin licensing check
- Recipe: Gate a sibling plugin behind entitlement — the bootstrap pattern feature plugins follow
- Per-button and per-role settings — the settings cascade behind role gating
- AJAX action: local_app_get_phone_data — the phone-data endpoint and its cursor parameter
What’s next
Once the content shows up for your test role, repeat step 3 for every other role that should see it (anonymous, subscriber, any custom plugin roles) — each role resolves settings and visibility on its own, so passing for one doesn’t guarantee the rest.
