Goal
Make the phone-data pipeline return your own fully-formed JSON response and skip every other subscriber. This is the right tool when a single-purpose app needs to serve a completely different response shape than the standard screen-graph — a maintenance/outage banner, a kiosk that only ever shows one screen, or a custom auth gate that must answer before the normal pipeline runs.
This is a full replacement, not an augmentation. If you only want to add or tweak data on top of the normal response, you are in the wrong article — use mam_get_phone_data_before_send instead (see What’s next).
Before you start
You should understand what you are bypassing. When the pipeline short-circuits, none of the following runs:
mam_get_phone_data_before_send(dozens of subscribers across the suite) and the whole content phase- the per-button enrichment loop (
mam_tab_manager,mam_final_button_settings) home_catsinjection (MAM_Main_Manager::manage_phone_data)- output shaping in
phase_finalize— includingmam_replace_null_with_empty_string(), subcategory cleanup (mam_clean_subcategories()), and notification cleanup (clean_notifications()) — as well as themam_json_validate()check that runs earlier in the content phase
You are taking full responsibility for a JSON-safe, mobile-parseable response.
Prerequisites:
mam-mainactive (the hook is part of theMAM_Phone_Data_Pipeline; this doc is verified against 26.29.15+).- A PHP extension point — typically a small use-case plugin or a site-specific mu-plugin — where you can register a filter.
- Familiarity with the response envelope the mobile client expects. Test against the Previewer; a degenerate shape can crash the app.
Key caution before you write any code
There is a contract detail in the current pipeline that is easy to miss and will silently no-op your filter if you ignore it.
The hook fires as:
$external_cached_json = apply_filters( 'mam_local_app_data', array(), $return_data );
The short-circuit only takes effect when $return_data is true — that is, when the phone data is being fetched via a direct PHP call ($return_data = true), not via the live AJAX request the mobile app makes. For a normal AJAX request the filter still fires (so subscribers can observe it), but its return value is discarded and the pipeline continues to the content phase.
What this means in practice:
- The short-circuit is a frozen contract that is reliably exercised on the direct PHP / programmatic path today.
- If you are depending on it to replace the live mobile AJAX response, verify the behavior in your target version first. As of the source this article was checked against, the AJAX path does not honor the return value, and there are no active subscribers in the wild. Do not assume; test with the Previewer and confirm against the version your client runs.
Treat this as the single most important thing to verify before you ship.
Steps
1. Decide whether replacement is really what you want
Confirm you need a replaced response, not an augmented one. If any part of the normal screen-graph (buttons, forms, notifications, home_cats) should still appear, do not short-circuit — hook mam_get_phone_data_before_send at the appropriate priority instead.
2. Register the filter
Add a filter on mam_local_app_data. Return an empty array to let the normal pipeline run, or a non-empty array to take over.
add_filter( 'mam_local_app_data', function ( $data, $return_data = false ) {
$maintenance_until = (int) get_option( 'mam_maintenance_until', 0 );
// Nothing to do — hand control back to the normal pipeline.
if ( $maintenance_until <= time() ) {
return $data; // empty array
}
// Return a minimal payload — this bypasses everything below.
return array(
'maintenance_mode' => true,
'message' => 'We will be back shortly.',
'retry_after_ts' => $maintenance_until,
);
}, 10, 2 );
Note the 2 accepted-args so you can read $return_data and behave consistently with the code-level contract above.
3. Honor the empty-array convention exactly
The “continue” signal is an empty array. Returning null or false is treated the same as “skip my override.” Returning a non-empty array is the only thing that triggers replacement. Do not return strings, objects, or truthy scalars.
4. Hand-build a JSON-safe, mobile-parseable response
Because output shaping does not run, you must do its job yourself:
- No
nullvalues in fields the older mobile parsers expect as strings — use"". - No closures, resources, or other non-JSON-encodable values anywhere in the array. These won’t fail until
wp_send_json(), and the failure will be opaque. - Match the envelope keys the app actually reads for your screen. Copy a real response from a normal pipeline run and trim it down rather than inventing keys.
5. Keep it single-subscriber
Subscribers do not compose. Because the hook is a normal filter chain, the last subscriber to return a non-empty array wins; values are never merged. If you ship a short-circuit, own it as the only one — do not stack two plugins both trying to replace the response.
6. Test in the Previewer, then on a device
Validate the exact shape end to end before any release. A short-circuit with an unrecognized shape can crash the mobile client. Confirm the path you depend on (direct PHP vs. live AJAX) actually returns your payload in your target version.
Gotchas
- The empty-array contract is binding.
null/falsemean “skip,” not “replace.” - No output shaping runs. You are fully responsible for null-stripping, JSON validity, and any push-notification hydration your screen needs.
- Last non-empty return wins. Don’t rely on merge semantics; there are none.
- Never use this to augment. Augmentation is
mam_get_phone_data_before_send. The short-circuit is full replacement only. - AJAX vs. direct-call behavior differs. Per the current source, the return value is honored on the direct-PHP path and discarded on the live AJAX path. Verify against your version.
What’s next
- To add to the normal response instead of replacing it: Hook: mam_get_phone_data_before_send — the standard extension point, with priority conventions for running before or after the default cohort.
- To understand exactly where this hook fires and what each phase does: Phone data pipeline phases.
- For the entry point that drives all of this: AJAX action: local_app_get_phone_data.
Related
- Hook: mam_local_app_data (the hook reference this how-to is built on)
- Phone data pipeline overview
- Phone data pipeline phases
- Hook: mam_get_phone_data_before_send
- Frozen public contracts reference
