Forms manager hook reference

Reading order

Each hook is listed in the order it fires during a full form lifecycle. Within each hook:

  • Type — filter (transforms value) vs action (side-effect only)
  • Signature — callback signature, (int, int) priority/argcount where the framework registers with non-default
  • Fires — what triggers it
  • Return — expected shape if a filter; ignored if an action
  • Use it when — what a sibling plugin would do here

Phase 1 — Plugin init / registration

These run when plugins load. They’re not in a single sequence — order depends on which plugin registers first.

Two parallel entry points, one per form source:

  • Code-based (programmatic) formsmam_form_manager_get_forms_from_plugins. Forms defined entirely in PHP. No Gravity Forms installation required. This is mam-main’s first-class native path
  • Gravity-Forms-backed formsmam_gf_get_form_settings. Forms built in the GF admin UI, bridged in by mam-gravity-forms-manager. Use when admins need to edit forms without code or when integrating with existing GF records

Pick whichever fits the use case; downstream phases (cache, fetch, prefill, submission) are identical for both.

mam_form_manager_get_forms_from_plugins

Type Filter
Signature apply_filters( 'mam_form_manager_get_forms_from_plugins', array $forms )
Fires When the framework collects code-based (non-Gravity-Forms) forms
Return Array of form definitions in the standard form-info shape
Use it when Your plugin defines a programmatic form fully in PHP — no Gravity Forms record exists or is needed
add_filter( 'mam_form_manager_get_forms_from_plugins', function ( $forms ) {
    $forms['my_internal_form'] = [
        'slug'   => 'my_internal_form',
        'fields' => [ /* ... */ ],
    ];
    return $forms;
} );

mam_gf_get_form_settings

Type Filter
Signature apply_filters( 'mam_gf_get_form_settings', array $settings )
Fires When the framework needs the slug-mapped form catalog (in the admin UI and during cache pre-warm)
Return Settings array with one entry per form, in the {category, title, variable, type, id, environment, data} envelope. See end-to-end cookbook
Use it when The form is backed by a Gravity Forms record (admin-editable or pre-existing). Requires mam-gravity-forms-manager + Gravity Forms. For PHP-only forms, use mam_form_manager_get_forms_from_plugins instead

mam_for_gravity_forms_form_result_form_<ID>

Type Filter (registration only — fires later in Phase 4)
Signature add_filter( 'mam_for_gravity_forms_form_result_form_' . get_option( '<form_settings_id>' ), $callback )
Fires (registration) At plugin init
Fires (callback) When the app submits this specific form
Gotcha get_option() must already be set when add_filter() runs. If your option is set later, register the filter on a later hook or use mam_gf_get_form_from_cache lazily

Phase 2 — Cache pre-warm

The framework hooks setup_forms_for_caching() onto mam_initial_phone_data. That triggers when the app first asks for phone data.

mam_initial_phone_data

Type Action
Signature do_action( 'mam_initial_phone_data' )
Fires Early in the phone-data build, before content classes run
Use it when You need to do prep work before any content class executes — e.g., warm your own caches alongside the form cache

Inside the framework’s handler (mam_for_gravity_forms_forms_manager::setup_forms_for_caching), per declared form:

form_id  = get_option( form_def.id )
if form_id > 0:
    build slug → field_id map from <form_def.id>_<slug> options
    form     = get_data_for_app(form_id)            ← fires Phase 3 hooks
    for each cached field:
        field = apply_filters( 'mam_form_manager_precached_field', field, form_id )
        if slug map has this field's id:
            field.populate_with_key = slug
    $local_app_form_array[] = form

mam_form_manager_precached_field

Type Filter
Signature apply_filters( 'mam_form_manager_precached_field', array $field, int $form_id )
Fires During cache pre-warm only, per field, after get_data_for_app has returned
Return The (possibly modified) field array
Use it when You need to tweak fields only during the pre-warm pass — rare. Most integrations should use mam_populate_gravity_form instead, which fires for both pre-warm and cache-miss paths
Gotcha Does not fire when a form is loaded via the cache-miss path of mam_gf_get_form_from_cache. If you depend on this hook, your changes silently disappear when the cache wasn’t pre-warmed

Phase 3 — Form fetch and shaping

local_app_gravity_forms::get_data_for_app( $form_id ) is the main shaper. It runs during pre-warm AND during cache-miss fetches. Hooks fire in the order below.

mam_gf_get_form

Type Filter
Signature apply_filters( 'mam_gf_get_form', array $form, int $form_id )
Fires At the very start of get_data_for_app — to fetch the raw GF form
Return The form array (['id' => …, 'fields' => […]]). Returning empty array short-circuits
Default callback mam_for_gravity_forms_forms_manager::get_gravity_form (reads from GFAPI)
Use it when You’re providing a custom form source — e.g., synthetic forms not backed by Gravity Forms records

mam_gf_get_custom_form

Type Filter
Signature apply_filters( 'mam_gf_get_custom_form', array $form, int $form_id )
Fires Inside get_gravity_form if the standard GF lookup didn’t find anything
Use it when You want a fallback source for forms that aren’t real GF records

mam_populate_gravity_form

Type Filter
Signature apply_filters( 'mam_populate_gravity_form', array $form, int $form_id )
Fires Inside get_data_for_app, right after the raw form is fetched, before field processing
Return The form array
Use it when The primary spot for runtime injection. Inject dropdown choices, set defaults, stamp populate_with_key, mutate field properties. Works for both pre-warm and cache-miss paths
Notable The framework’s web-only gform_pre_render does NOT fire for app-bound forms. This is its replacement

mam_form_manager_content_class_<type>

Type Filter
Signature apply_filters( "mam_form_manager_content_class_{$form_type}", array $field, $rawField, $form, $isRequired )
Fires Per field, after standard shape is built
Return The field array
Use it when You’re owning a custom field type and need to control its on-wire shape. mam-gravity-forms-manager uses mam_form_manager_content_class_form for nested-form fields

mam_populate_gravity_form_final

Type Filter
Signature apply_filters( 'mam_populate_gravity_form_final', array $form )
Fires Last per-form transformation in get_data_for_app, after all per-field work
Use it when Final cleanup or whole-form tweaks

mam_gf_populate_form_data_with_post_meta

Type Filter
Signature apply_filters( 'mam_gf_populate_form_data_with_post_meta', array $form, array $post_meta )
Fires When the form is being rendered against a specific post’s meta
Use it when Form is editing a CPT and field defaults should come from get_post_meta

mam_update_form_before_sending_<formid>

Type Filter
Signature apply_filters( "mam_update_form_before_sending_{$form_id}", array $form )
Fires Just before the form payload exits get_data_for_app
Use it when Form-id-specific last-mile transform

mam_update_form_before_sending

Type Filter
Signature apply_filters( 'mam_update_form_before_sending', array $form )
Fires Final transform before return
Use it when Universal last-mile transform (not form-id-specific)

Phase 4 — Row → form lookup

Content classes call this when they’re publishing a row that references a form.

mam_gf_get_form_from_cache

Type Filter
Signature apply_filters( 'mam_gf_get_form_from_cache', $current_value, int $form_id )
Fires When a content class asks for a form’s cache index
Return 1-based index into $local_app_form_array, or false if the form couldn’t be loaded
Gotcha If the form isn’t already cached, this triggers a get_data_for_app call — and the result lands in $local_app_form_array without populate_with_key stamping (that only happens in the pre-warm path). Use mam_populate_gravity_form to stamp populate keys yourself for cache-miss resilience
$form_index = apply_filters( 'mam_gf_get_form_from_cache', 0, $form_id );
if ( $form_index ) {
    $row['form_id'] = (string) $form_index;
}

Phase 5 — Submission handling

When the app POSTs a submission, mam_gf_submit_app_form processes it. The form’s handler runs through a form-id-keyed filter.

mam_for_gravity_forms_form_result_form_<ID>

Type Filter
Signature add_filter( "mam_for_gravity_forms_form_result_form_{$gf_form_id}", $callback ) — handler receives ( $result = null, $entry = null, $form = null )
Fires Once per submission for that specific form ID
Return The standard result envelope (see end-to-end cookbook §5b)
Use it when Always — this is the submission entry point

mam_gf_get_form_data

Type Filter
Signature apply_filters( 'mam_gf_get_form_data', array $fields, string $slug_root_with_underscore )
Fires Called from inside your submission handler
Return [ slug => [ 'value' => x, ...meta ], ... ]
Use it when Always — easiest way to pull submission values keyed by your slugs instead of GF field IDs
$values       = apply_filters( 'mam_gf_get_form_data', $fields, 'mam_aquaman_day_settings_' );
$booking_date = $values['booking_date']['value'] ?? '';

Note the trailing underscore — the framework expects it. Forgetting it makes every lookup miss.

mam_form_manager_send_notifications

Type Action
Signature do_action( 'mam_form_manager_send_notifications', $entry, $form )
Fires After your handler returns, only if send_notifications => true in the result envelope
Use it when You want to plug into the standard notification dispatcher

mam_gravity_forms_after_form_processed

Type Action
Signature do_action( 'mam_gravity_forms_after_form_processed', $entry, $form )
Fires After the full submission pipeline completes, regardless of handler outcome
Use it when Side-effect work (logging, cleanup) that always runs after every submission

mam_for_gravity_forms_form_submitted_<ID>

Type Filter
Signature apply_filters( "mam_for_gravity_forms_form_submitted_{$gf_form_id}", $entry )
Fires After the result handler, before the notification dispatch
Use it when You need to mutate the entry between handler return and notifications firing

The $local_app_form_array global

The cache. A simple indexed array of cached form arrays. Three rules:

  1. Push, don’t insert — always append; don’t reorder. Existing rows reference forms by 1-based index
  2. 1-based indexing on the wire$local_app_form_array[0] is reachable via form_id: "1". get_form_from_cache returns (string) ( $index + 1 )
  3. One copy per form_idget_form_from_cache deduplicates by $form['formid']. Don’t push the same form_id twice

Forms in this array carry their fully-shaped payload, including choices, populate_with_key, and any custom keys you added via mam_populate_gravity_form. After phone-data assembly, this global is serialized into the mobile JSON’s form_data array.


Option-key conventions

Option key Holds Set by
<form_settings_id> GF form ID for this declaration (e.g., 3) App admin UI’s form-settings page
<form_settings_id>_<field_slug> GF field ID for that slug (e.g., 1) Same page, per declared field
mam-form-cache-* Serialized form-definition cache mam_form_manager_cache_manager, invalidated on form save / option change

The first two are the load-bearing convention. If populate_with_key isn’t appearing, walk through these options and verify each one has a value > 0.


Common firing-order gotchas

Submission handler isn’t firing

add_filter( 'mam_for_gravity_forms_form_result_form_' . get_option( 'foo' ), ... ) — when this line runs, get_option('foo') must already return the form ID. If your plugin loads before the option is set, the filter is registered with an empty form ID and never fires. Two fixes:

  1. Set the option (via the admin UI) before deploying the plugin
  2. Register late: hook your form-manager init onto init or plugins_loaded priority 20+, after the option is reliably set

populate_with_key is missing from the cached form

Three checks, in order:

  1. Is <form_settings_id>_<slug> set to a positive GF field ID? If no, the framework can’t resolve the slug
  2. Did the pre-warm run? mam_initial_phone_data must fire before anyone calls mam_gf_get_form_from_cache. If your content class is invoked from an earlier hook, the form gets loaded via the cache-miss path which skips populate-key stamping
  3. Are you stamping populate_with_key yourself in mam_populate_gravity_form as belt-and-suspenders? Recommended for any new form

Choices keep getting overwritten

gform_pre_render and related GF web hooks do NOT fire for app-bound forms. If you set choices in those hooks they only apply on the web side. Move the logic to mam_populate_gravity_form.

Field arrives as object vs array

Some code paths hand you a GF_Field object; others hand you an array. Defensive code:

$fid = (int) ( is_object( $field ) ? ( $field->id ?? 0 ) : ( $field['id'] ?? 0 ) );

mam_form_manager_precached_field runs but my logic doesn’t

That hook only fires on the pre-warm pass. Cache misses skip it. Move to mam_populate_gravity_form.


See also


Metadata

Field Value
Article type Reference
Plugin slug mam-main
Applies to plugin version 2.1.11+
Category Forms Manager
Audience PHP developer
Last verified 2026-05-20
Related End-to-end cookbook, Forms manager overview
Contents

    Need Support?

    Can’t find the answer you’re looking for? Don’t worry we’re here to help!