Hook: mam_main_iap_subscription_has_changed

Purpose

Fires when the in-app purchase product reported by the app changes — a user upgrades, downgrades, or switches products. Sibling plugins (typically mam-inapp-purchase-manager) update entitlements, gate features, or dispatch notifications.

The action fires during the phone-data build (in mam-main’s JSON manager) when the request’s iap_product differs from the stored iap_product usermeta, just before the new value is persisted.


Signature

do_action(
    'mam_main_iap_subscription_has_changed',
    int    $user_id,
    string $previous_product_id
);
Parameter Type Description
$user_id int The user whose subscription changed
$previous_product_id string The iap_product usermeta value before the change (the old product id)

The action fires only when the incoming iap_product request value differs from the stored iap_product usermeta. Read the new product id from the request / from usermeta after the pipeline persists it (get_user_meta( $user_id, 'iap_product', true )).


Example: persist new entitlement state

add_action( 'mam_main_iap_subscription_has_changed',
    function ( int $user_id, string $previous_product_id ) {

        // The new product id has been written to usermeta by the pipeline.
        $new_product_id = get_user_meta( $user_id, 'iap_product', true );

        update_user_meta( $user_id, "iap_changed_at", current_time( 'mysql' ) );

        do_action( 'mam_notification_send_message', array(
            'message_type' => 'mam-my-plugin-iap_changed',
            'recipient_id' => $user_id,
            'replacements' => array(
                'previous_product' => $previous_product_id,
                'new_product'      => $new_product_id,
            ),
        ) );
    },
    10, 2
);

Pipeline integration

mam-main’s own JSON manager (main-json-manager.php) processes the app’s reported iap_product on each phone-data build. When the request’s iap_product differs from the stored iap_product usermeta, it fires this action, then persists the new value. Subscribers see the change in (near) real-time.


Gotchas

  • Fires per-phone-data-request. A user with a long-running session may not see the action fire until they next launch the app or the cursor is invalidated.
  • No retry. If your subscriber’s persistence fails, the action doesn’t fire again unless the state changes again.
  • product_id shapes vary by store. Apple uses reverse-DNS (com.example.subscription_monthly); Google uses arbitrary strings. Don’t assume a format.
  • The action carries the old product id only. It fires on any change of the reported iap_product (upgrade, downgrade, switch) — it does not carry a state enum. Read the new product id from usermeta.
  • No transactional guarantee. Two simultaneous phone-data requests for the same user could both detect the same shift and both fire the action — guard your subscriber against double-application.

  • Phone data pipeline phases
  • Hook: mam_get_phone_data_before_send
  • Hook: mam_notification_send_message

Metadata

Field Value
Article type Hook Reference
Plugin slug mam-main
Applies to plugin version 2.1.11+
Hook type action
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!