What it does
notifications-manager (includes/notifications-manager/) is the single entry point for sending notifications across email, SMS, and push channels. After Phase 2.2, the architecture is:
do_action('mam_notification_send_message', $message)
│
▼
MAM_Notification_Dispatcher::handle_action()
│ (batches route through dispatch_batch() → dispatch_one())
┌────────────┼────────────┐
▼ ▼ ▼
Email SMS Push
Sender Sender Sender
│ │ │
wp_mail() Twilio APNs / FCM
or queue or queue via MAM_PushDispatcher
Channel routing is driven by the mam_notification_list filter — a registry of notification types, each declaring which channels it supports plus per-channel templates.
Public surface
| Class | Role |
|---|---|
MAM_Notification_Dispatcher |
Single entry point — receives mam_notification_send_message, normalises input, routes per-message |
MAM_Notification_Message |
Input value object (recipient, type, channel hints, replacements) |
MAM_Notification_Result |
Output value object (per-channel status + errors) |
MAM_Email_Sender / MAM_Sms_Sender / MAM_Pn_Sender |
Per-channel senders |
mam_message_and_notification_manager |
Admin UI + custom-notification triggering |
mam_notifications_outbox_viewer |
Admin grid showing recent dispatches |
mam_notifications_list |
Registers the four bundled core notification types |
Hooks fired
| Hook | Type | Purpose |
|---|---|---|
mam_notification_send_message |
Action (+ legacy filter) | Primary entry point. Fire to dispatch a notification |
mam_notification_send_pn |
Action | Push-only channel hook |
mam_update_pn_status |
Action | Vestigial — registered, no fire sites |
mam_cron_manager |
Filter | Notification system registers the queue-processor cron |
mam_custom_notifications |
Action | Cron-fired hook for scheduled custom notifications |
mam_notification_list |
Filter | Notification-type registry — 68+ subscribers register types here |
mam_notification_save_notification_type |
Filter | Admin-side type save |
mam_notifications_notification_types |
Filter | Type listing for the admin UI |
mam_get_phone_data_before_send |
Filter | Subscriber mam_notification_manager::manage_phone_data injects in-app notification list |
DB tables (owned)
| Table | Purpose |
|---|---|
wp_mam_notification_history |
In-app notification delivery log |
wp_mam_sms_queue |
Unified PN + SMS queue, channel flag distinguishes |
wp_mam_mail_queue |
Email queue (owned by mail-cron-manager) |
wp_mam_mail_attachments |
Email attachment storage |
All renamed from wp_tsl_* in PR #31; backward-compat aliases via MAM_Migration_Tasks. Frozen contract — do not rename without aliasing migration.
Three-channel routing
MAM_Notification_Dispatcher::dispatch_one() routes per channel:
For each message, look up the type definition in mam_notification_list.
If phone present (in message OR billing_phone usermeta) AND
(tsl_notification_text_status_{slug} option is on OR type's default_on includes 'sms'):
MAM_Sms_Sender::send()
If email present (or recipient_id resolves to a user with email) AND
(tsl_notification_email_status_{slug} option is on OR type's default_on includes 'email'):
MAM_Email_Sender::send()
If recipient_id present AND
(tsl_notification_pn_status_{slug} option is on OR type's default_on includes 'push'):
MAM_Pn_Sender::send()
Per-channel opt-in is per-type. Admins toggle in Mobile App Manager → Notifications → Settings.
⚠️ Naming inconsistency — the dispatcher reads tsl_notification_*_status_* option keys, but REFACTOR_PLAN.md documents that these were renamed to mam_notification_*_status_* in PR #32. The migration framework’s option aliases mean reads to either name return the same value, so behavior is unchanged. Code uses the legacy tsl_* prefix; the framework redirects.
Cron / immediate dispatch
The dispatcher decides per batch:
$use_cron_if_available = count( $messages ) > 10;
$use_global_cron = get_option( 'mam_notification_use_cron' ) == 1;
$use_cron = $use_cron_if_available && $use_global_cron;
Threshold: cron only kicks in for batches of >10 AND when mam_notification_use_cron is on. Smaller batches and non-cron sites send immediately.
See Notification queue and cron.
The legacy add_filter registration
mam_notification_send_message is registered both as add_action (modern) AND add_filter (legacy). The dual registration bridges:
- Modern callers —
do_action('mam_notification_send_message', $msg)discards the return. - Legacy callers —
apply_filters('mam_notification_send_message', $msg)reads the handler’sstatusreturn.
The add_filter registration is retained as SC #175 deferred — it bridges legacy apply_filters callers in mam-account-manager and customer-site copies of older plugins. Removable once a deprecation cycle confirms no remaining wild callers.
Bundled notification types
| Slug | Purpose | Default channels |
|---|---|---|
mam-user-roles-welcome_email |
Sent on first user registration | (off — admin enables) |
mam-user-roles-lost_password |
Password-reset code | |
mam-user-roles-login-with-email |
Email signup verification code | |
mam-push-notification |
Generic PN — used by sibling plugins as a fallback | (off — admin enables) |
Plus 60+ types registered by sibling plugins.
Gotchas
- Don’t fire
mam_notification_send_messagedirectly from form-handling code. Go throughmam_form_manager_send_notificationsso admin overrides can intercept. - Don’t fire
mam_notification_send_pndirectly unless you’re in thesystem_chatspecial path. Usemam_notification_send_messageand let the dispatcher route. - Per-message
send_text/send_email/send_pnflags were inert and are removed (PR #34). Channel routing comes from the type registry. - Plaintext credentials for APNs/FCM are a known hardening gap.
- *Frozen `mam_` table names** — never rename in place.
Related articles
- Plugin: mam-main
- Notification types registry
- Notification channels: email, SMS, push
- Notification queue and cron
- Notification history and opt-out
- Notification template replacements
- Recipe: Register a notification type
- Hook: mam_notification_send_message
- Hook: mam_notification_send_pn
- Hook: mam_notification_list
- Hook: mam_custom_notifications
- Frozen public contracts reference
Metadata
| Field | Value |
|---|---|
| Article type | Plugin Overview |
| Plugin slug | mam-main |
| Applies to plugin version | 2.1.11+ |
| Category | Plugin Reference |
| Audience | PHP developer |
| Last verified | 2026-05-02 |
