What it does
mam-main treats forms as a pluggable provider model. Multiple form sources can coexist behind one set of mobile-app-facing concepts. The forms-manager subsystem doesn’t care where a form definition came from — it just needs a provider that can answer: what fields does this form have, how do I render it for the mobile app, how do I process a submission against it.
Two providers ship today:
| Provider | Where it lives | Maturity |
|---|---|---|
| Gravity Forms | mam-gravity-forms-manager (separate plugin) + GF-aware code in mam-main/includes/forms-manager/ |
Mature; most customer sites use this |
| Programmatic forms | Plugin code that registers forms via filter | Lightweight; used for things like the user profile form, geodirectory invitations, listing claim forms |
The architecture is extensible to additional providers (e.g., Ninja Forms) by hooking the same extension surface. None of the mobile-app rendering or submission code is GF-specific at the API level — only the implementation layer behind the hooks is.
The two hook namespaces
mam-main has two parallel form-related hook surfaces. This is a historical artifact: the system was originally Gravity-Forms-only, so the first generation of hooks were named mam_gf_* and mam_for_gravity_forms_*. As the abstraction generalized, a mam_form_manager_* namespace was added. Both still fire today.
Modern generic surface — mam_form_manager_* (prefer for new code)
| Hook | Type | Role |
|---|---|---|
mam_form_manager_get_forms_from_plugins |
Filter | Primary registration hook. Sibling plugins return their custom (non-GF) forms here |
mam_form_manager_get_from_plugins |
Filter | Per-plugin retrieval helper |
mam_form_manager_form_submitted_<form-id> |
Filter (dynamic) | Per-form submission handler |
mam_form_manager_send_notifications |
Action | Submission post-process — subscribers fire do_action('mam_notification_send_message', …) here |
mam_form_manager_precached_field |
Filter | Per-field pre-cache hook |
mam_form_manager_process_field_type_<type> |
Filter (dynamic) | Per-field-type custom processor — sibling plugins implement custom field types here |
mam_form_manager_content_class_<class> |
Filter (dynamic) | Per-content-class form integration |
Legacy Gravity-Forms-flavored surface — mam_gf_* / mam_for_gravity_forms_* (still load-bearing)
These names predate the provider abstraction. They still fire and many sibling plugins subscribe to them, so they cannot be renamed without a coordinated migration. Use them when you need data the modern generic surface doesn’t yet expose.
| Hook | Type | Role |
|---|---|---|
mam_gf_get_form |
Filter | Single form fetch by id |
mam_gf_get_all_forms |
Filter | All known forms |
mam_gf_get_form_data |
Filter | Form data block (fields + values) |
mam_gf_get_form_settings |
Filter | Form settings block |
mam_gf_get_custom_form |
Filter | Single custom-form fetch |
mam_gf_get_custom_forms_list |
Filter | All custom forms |
mam_gf_get_cpt_for_form_id |
Filter | Resolve associated post type |
mam_gf_processing_form |
Action | Fired when a submission begins processing |
mam_gf_populate_form_data_with_post_meta |
Filter | Post-meta hydration |
mam_gf_settings_tab_tabs_list |
Filter | Inject custom tabs into the GF settings page |
mam_gf_settings_tab_content |
Filter | Render content for a custom tab |
mam_gf_user_profile_submit_title |
Filter | Submit-button title on profile form |
mam_for_gravity_forms_form_submitted_<form-id> |
Filter (dynamic) | Per-form GF submission handler |
mam_for_gravity_forms_form_result_form_<form-id> |
Filter (dynamic) | Per-form result builder |
mam_for_gravity_forms_form_result / _v2 |
Filter | Generic result builder |
mam_populate_gravity_form |
Filter | Initial transformation pass |
mam_populate_gravity_form_final |
Filter | Final transformation pass |
mam_gravity_forms_after_form_processed_<form-id> |
Filter (dynamic) | Per-form post-process |
mam_update_form_before_sending |
Filter | Last-chance pre-send mutation (already generic-named) |
Frozen public contracts. The legacy
mam_gf_*andmam_for_gravity_forms_*hook names are public API. Customer-site sibling plugins subscribe to them. They cannot be renamed in mam-main without breaking customer installations. Any rename has to come with a deprecation cycle and a sweep of every external repo (mam-suite-hold, mam-use-case, customer-site copies). Tracked as post-launch refactor work.
Recommended usage matrix
When writing new code that needs to interact with forms in mam-main:
| Goal | Use this hook |
|---|---|
| Register your plugin’s custom (non-GF) forms | mam_form_manager_get_forms_from_plugins |
| Handle a specific form’s submission | mam_form_manager_form_submitted_<form-id> |
| Send notifications after a submission | do_action('mam_form_manager_send_notifications', ...) (then dispatcher routes to email / push / SMS) |
| Process a custom field type at build time | mam_form_manager_process_field_type_<type> |
| Fetch a form definition (id-keyed) | mam_gf_get_form (no generic counterpart yet) |
| Fetch all known forms | mam_gf_get_all_forms (no generic counterpart yet) |
| Mutate a form payload before send | mam_update_form_before_sending (already generic) |
Where the matrix says “no generic counterpart yet”, the legacy hook is the only option. This is a known gap; closing it is straightforward (a small alias layer in mam-main.php) and tracked as a pre-launch nice-to-have.
Adding a new form provider
The minimal contract: a provider registers its forms via mam_form_manager_get_forms_from_plugins, and provides handlers that respond when one of its forms is fetched, submitted, or processed.
Skeleton
add_filter( 'mam_form_manager_get_forms_from_plugins', function ( array $forms ): array {
// Append your provider's forms to the registry. Each entry is keyed by
// form id and carries enough metadata for the mobile-app pipeline to
// know the form exists.
foreach ( my_provider_get_forms() as $form ) {
$forms[ $form['id'] ] = array(
'id' => $form['id'],
'title' => $form['title'],
'provider' => 'my-provider',
'fields' => my_provider_normalize_fields( $form['fields'] ),
);
}
return $forms;
} );
// Handle this provider's forms when fetched by id.
add_filter( 'mam_gf_get_form', function ( $form, $form_id ) {
if ( $form ) {
return $form; // Already resolved by another provider — defer.
}
return my_provider_lookup_form( $form_id ); // Returns array or null.
}, 10, 2 );
// Handle a submission against one of this provider's forms.
add_filter( 'mam_form_manager_form_submitted_' . MY_PROVIDER_FORM_ID, function ( $result, $submission ) {
return my_provider_process_submission( $submission );
}, 10, 2 );
Field types
If the provider introduces custom field types the mobile app should render, register a per-type processor:
add_filter( 'mam_form_manager_process_field_type_my-custom-field', function ( $field, $args ) {
// Convert the provider's field shape into the mobile-app render shape.
return my_provider_render_field( $field, $args );
}, 10, 2 );
Notifications
After processing a submission, fire the generic notifications hook so admin overrides can intercept and the configured channels (email, SMS, push) all dispatch consistently:
do_action( 'mam_form_manager_send_notifications', $submission_result, $form_id );
Do not fire mam_notification_send_message directly from form-handling code. Always go through mam_form_manager_send_notifications so the dispatch flow stays uniform across providers.
How discovery resolves across providers
When the phone-data pipeline asks “what forms exist,” the resolution order is:
- Gravity Forms native discovery (
mam-gravity-forms-managerplugin) mam_form_manager_get_forms_from_plugins— every registered provider appends its formsmam_add_prog_form/mam_generated_forms— programmatic forms registered by user-roles, geodirectory, etc.- Caching layer reads from
mam-form-cache-*options to skip repeated discovery
A form id collision between providers is undefined behavior — each provider should namespace its form ids (e.g., nf-123, prog-user-profile) to avoid stepping on others.
Why the asymmetry exists
When mam-main shipped, Gravity Forms was the only form integration. Hooks were named mam_gf_* because there was nothing else to be generic about. As Ninja Forms support, programmatic forms, and the broader provider model came in, a parallel mam_form_manager_* namespace was added — but the original mam_gf_* hooks couldn’t be renamed without breaking every sibling plugin that already subscribed to them.
The result: two namespaces that mostly agree on what each hook does, with the legacy one having more coverage and the modern one being the recommended target for new code. Closing the gap is a post-launch cleanup task that requires:
- Adding
mam_form_manager_*aliases for the missing legacy hooks - Sweeping ~300 touch points across mam-suite, mam-suite-hold, mam-use-case, and customer-site plugin copies
- A deprecation cycle (
_deprecated_hook()warnings for one release)
Frozen public contracts in this article
| Hook | Why it cannot be renamed |
|---|---|
mam_gf_get_form, mam_gf_get_all_forms, mam_gf_get_form_data, mam_gf_get_form_settings, mam_gf_get_custom_form, mam_gf_get_custom_forms_list, mam_gf_get_cpt_for_form_id |
Sibling plugins subscribe to fetch form data |
mam_gf_processing_form |
Sibling plugins hook submission start |
mam_for_gravity_forms_form_submitted_<id> |
Per-form submission contract; customer plugins subscribe by form id |
mam_gravity_forms_after_form_processed_<id> |
Per-form post-process contract |
mam_populate_gravity_form / mam_populate_gravity_form_final |
Customer plugins use these to mutate form payloads |
When in doubt: wrap, don’t rename.
See also
04a-forms-manager-overview.md— what forms-manager is and how it bridges into the mobile app04b-form-submission-lifecycle.md— the end-to-end submission flow04c-custom-field-types.md— registering a custom field-type processor04d-form-cache-and-invalidation.md— how cached form definitions are kept freshmam_notification_send_message(notifications hook reference) — whatmam_form_manager_send_notificationsultimately dispatches into
Metadata
| Field | Value |
|---|---|
| Article type | Architecture Reference |
| Plugin slug | mam-main |
| Applies to plugin version | 2.1.11+ |
| Category | Plugin Reference |
| Audience | PHP developer |
| Last verified | 2026-05-02 |
