Goal
Register a new notification type so it appears in Mobile App Manager → Notifications → Settings, can be templated by the admin, and can be fired from your sibling plugin.
Prerequisites
- A sibling plugin with its own slug (e.g.,
mam-my-plugin) - An event that should trigger a notification (a form submission, a status change, a scheduled job)
Steps
1. Choose a slug
Convention: <plugin-slug>-<event-name>. Example: mam-my-plugin-order_shipped.
This becomes the message_type value when firing.
2. Register the type
add_filter( 'mam_notification_list', function ( array $data ): array {
$data[] = array(
'source' => 'mam-my-plugin',
'title' => 'Order Shipped',
'slug' => 'mam-my-plugin-order_shipped',
'replacements' => array( 'order_id', 'tracking_number', 'user_login' ),
'default_content' => 'Your order [order_id] has shipped. Track at [tracking_number].',
'default_on' => array( 'email', 'push' ),
'description' => 'Sent when an order is fulfilled and a shipping label is generated.',
);
return $data;
} );
After this, the type appears in the admin UI.
3. (Optional) Set per-channel templates programmatically
The admin UI is the canonical way to set templates. If your plugin needs to seed defaults on activation:
register_activation_hook( __FILE__, function () {
$slug = 'mam-my-plugin-order_shipped';
if ( ! get_option( 'tsl_notification_subject_' . $slug ) ) {
update_option( 'tsl_notification_subject_' . $slug, 'Your order has shipped' );
}
if ( ! get_option( 'tsl_notification_email_text_' . $slug ) ) {
update_option( 'tsl_notification_email_text_' . $slug,
"Hi [user_login],nnYour order [order_id] has shipped.nnTrack: [tracking_number]" );
}
} );
Use tsl_* prefix even though Phase 3 documented the rename — the framework’s option aliases handle both names but tsl_* matches what the dispatcher reads.
4. Fire the notification
do_action( 'mam_notification_send_message', array(
'message_type' => 'mam-my-plugin-order_shipped',
'recipient_id' => $user_id,
'replacements' => array(
'order_id' => $order_id,
'tracking_number' => $tracking,
),
) );
Built-in tokens like [user_login] are auto-hydrated from $user_id. Custom tokens must be supplied.
5. Verify in the admin
- The type appears in Mobile App Manager → Notifications → Settings → Order Shipped
- Per-channel toggles can be flipped
- Templates can be edited
6. Test send
Mobile App Manager → Notifications → Test Send → pick your type → pick recipient → send.
Verify the result in Mobile App Manager → Notifications → Outbox.
7. Verify in the in-app history
The Open Notifications content class on the device should show the new in-app notification (assuming in_app is implicitly enabled — most types are).
Verification
- Type appears in the admin UI
- Per-channel toggles persist
- A test send produces rows in the outbox for each enabled channel
- The in-app notification center shows the entry
- Replacement tokens are substituted correctly in delivered messages
Common pitfalls
- Slug collision — if another plugin (or a previous version of your plugin) registered the same slug, your new registration may be silently overridden. Check the registry:
print_r( apply_filters( 'mam_notification_list', array() ) ). - Forgetting
default_on— without it, the type is registered but every channel is off by default. Admins have to enable each one. - Custom replacements not declared — if you supply
[order_id]at fire time but didn’t declareorder_idin the type’sreplacementsarray, the substitution still works but the admin UI doesn’t show the token as available in its template-editor hint list. - Don’t fire
mam_notification_send_pndirectly. Usemam_notification_send_messageand let the dispatcher route — that respects per-channel opt-in and writes the history row.
Related articles
- Notifications overview
- Notification types registry
- Notification template replacements
- Hook: mam_notification_list
- Hook: mam_notification_send_message
Metadata
| Field | Value |
|---|---|
| Article type | Recipe (Developer) |
| Plugin slug | mam-main |
| Applies to plugin version | 2.1.11+ |
| Category | Extending MAM Suite |
| Audience | PHP developer |
| Estimated time | 15–30 minutes |
| Last verified | 2026-05-02 |
