Hook: mam_user_roles_save_addl_user_profile_field_{key}

Purpose

Per-field save filter for additional user profile fields registered via mam_add_fields_to_user_profile. Use this dynamic per-field hook — not the generic save hook — for per-field validation and persistence. Hooking the generic save and switching on field key is an anti-pattern that’s hard to extend.


Signature

$value = apply_filters(
    'mam_user_roles_save_addl_user_profile_field_' . $key,
    $value
);
Parameter Type Description
$value mixed The submitted raw value

Returns: mixed — the (possibly normalized) value.

The filter passes only $value — no $user_id. Resolve the user being saved yourself (e.g. MAM_Current_Request::get_user_id()) before calling update_user_meta().


Example: validate and persist a loyalty id

add_filter( 'mam_user_roles_save_addl_user_profile_field_my_plugin_loyalty_id',
    function ( $value ) {

        $user_id = MAM_Current_Request::get_user_id();

        // Normalize.
        $clean = preg_replace( '/[^A-Z0-9]/i', '', (string) $value );

        // Validate length.
        if ( $clean !== '' && ( strlen( $clean ) < 6 || strlen( $clean ) > 12 ) ) {
            // Don't persist invalid value; signal an error somehow
            // (note: this filter doesn't have a structured error channel —
            // use mam_user_roles_modify_user_profile_values_before_save for veto).
            return get_user_meta( $user_id, 'my_plugin_loyalty_id', true );
        }

        // Persist (yes — explicitly call update_user_meta).
        update_user_meta( $user_id, 'my_plugin_loyalty_id', $clean );

        return $clean;
    }
);

⚠️ You must call update_user_meta yourself. This filter doesn’t auto-persist. Returning a value alone won’t write it.


When to use vs. the broader hook

Hook Use when
mam_user_roles_save_addl_user_profile_field_{key} (this) Single field, per-field save logic
mam_user_roles_modify_user_profile_values_before_save Cross-field validation, veto, batch transforms

The dynamic per-field hook is the recommended pattern. The broader filter is for cases where a save depends on multiple fields together.


This filter doesn’t have a structured error channel. To reject an invalid value with a user-facing message:

  1. Use mam_user_roles_modify_user_profile_values_before_save (filter on the entire payload — return modified or veto)
  2. Or use a per-form result builder that runs validation before the save (mam_for_gravity_forms_form_result_form_{form-id}) for forms-driven profile updates

Gotchas

  • You must persist explicitly. Returning a value doesn’t auto-write. Call update_user_meta() inside the callback.
  • {key} in the filter name matches the field’s key from mam_add_fields_to_user_profile. Mismatch silently doesn’t fire.
  • No error channel. Validation failures need a different path.
  • Empty values are still passed through. Decide whether empty means “delete the meta” or “preserve existing”.
  • Fires for every save, including no-op saves where the value didn’t change. Cheap callbacks only.

  • Hook: mam_add_fields_to_user_profile
  • Hook: mam_user_roles_after_create_user
  • Recipe: Customize onboarding

Metadata

Field Value
Article type Hook Reference
Plugin slug mam-main
Applies to plugin version 2.1.11+
Hook type filter (dynamic — {key} is the field’s usermeta key)
Audience PHP developer
Last verified 2026-05-02
Was this article helpful?
Contents

    Need Support?

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