Purpose
The cron-task registry. Sibling plugins register their scheduled tasks by appending entries to the array passed through this filter. The mam_setcron_processor AJAX endpoint (pinged by FastCron on every tick) walks the registry and dispatches each task whose stored next_run is due.
~19 subscribers across mam-main, mam-suite-hold and the use-case plugins.
Signature
$crons = apply_filters( 'mam_cron_manager', array $crons );
| Parameter | Type | Description |
|---|---|---|
$crons |
array | A numerically-indexed list of cron definition arrays (append with $crons[] = …, not keyed by id) |
Returns: array — the augmented list.
Cron entry shape
array(
array(
'action' => 'my_plugin_nightly_sync', // dispatch hook name (unique)
'name' => 'My Plugin: Nightly Sync', // human-readable label
'frequency' => '60', // interval in MINUTES
'run_at' => '0200', // optional HHMM anchor time
),
// ...
)
| Field | Purpose |
|---|---|
action |
The dispatch hook name — invoked via apply_filters($action, array()). Must be unique site-wide. |
name |
Human-readable label for the admin grid |
frequency |
Interval in minutes (intval, defaults to 60). This is not a 5-field cron expression. |
run_at |
Optional HHMM time-of-day anchor for the first run |
The action value is the dispatch handle. There is no title / expression / callback
field, and the array is a flat list, not a map keyed by id.
Example: register a cron
add_filter( 'mam_cron_manager', function ( array $crons ): array {
$crons[] = array(
'action' => 'my_plugin_nightly_sync',
'name' => 'My Plugin: Nightly Sync',
'frequency' => '1440', // once a day (minutes)
'run_at' => '0200', // anchored to 2am
);
return $crons;
} );
// The callback registered against the dispatch hook (the `action` value):
function my_plugin_nightly_sync_action( $result = array() ) {
// do the work
// return the (optionally updated) $result array; the processor stamps
// last_run / next_run onto it
return $result;
}
add_filter( 'my_plugin_nightly_sync', 'my_plugin_nightly_sync_action' );
⚠️ Note: per-cron callbacks are invoked via apply_filters( $action, array() ), not do_action. The processor reads back last_run / next_run from the returned array, so return an array.
How dispatch works
mam_setcron_manager::mam_setcron_processor():
On every FastCron tick (typically every 1–5 minutes):
1. Resolve current time + timezone (wp_timezone_string(), with offset handling)
2. $crons = apply_filters('mam_cron_manager', array());
3. For each cron entry (keyed off its `action`):
- Load per-cron state from get_option($action) (last_run / next_run)
- First run: seed next_run (using `run_at` if present)
- If next_run is due (< now): apply_filters($action, array())
- Stamp last_run = now, next_run = now + frequency minutes
Multiple crons due on the same tick run serially.
Scheduling gotchas
frequencyis minutes, not cron syntax. There is no minute/hour/day-of-week expression — just an interval in minutes plus an optionalrun_atHHMM anchor.- Time zone matters. The processor sets PHP’s default TZ from
wp_timezone_string()for the duration of the tick (restored on shutdown). A site set toAsia/Kolkata(+05:30) evaluatesrun_atin IST. - Off-set zones (e.g.,
+05:30) fall back through twotimezone_name_from_abbrattempts, then to UTC. Use named timezones where possible. - FastCron’s resolution is the real ceiling — if FastCron pings every 5 minutes, a
frequencyof1still only fires every 5 minutes.
Common cron tasks
action |
Source | Purpose |
|---|---|---|
mam_mail_handler |
mam_mail_manager (frequency 1) |
Drain email + PN/SMS queues |
mam_custom_notifications |
mam_message_and_notification_manager |
Scheduled custom notifications — currently commented out in mam_cron_manager, so not registered by default |
| (sibling-plugin specific) | various | Per-plugin scheduled work |
Gotchas
actionmust be unique. Two entries sharing anactionshare the sameget_option($action)state row and both dispatch — schedules collide unpredictably.apply_filtersnotdo_action. The callback is invoked asapply_filters($action, array())and its returned array is read back forlast_run/next_run, so always return an array.- No retry semantics. A failed cron callback isn’t retried until its
next_runcomes due again. - Long-running callbacks block other crons on the same tick. Keep work short or move to a queue + drain pattern.
- Time-zone resolution can silently fall through to UTC for offset-style timezones.
- FastCron must be configured for crons to fire — see Integration: FastCron.
Related articles
- Integration: FastCron
- Notification queue and cron
- Recipe: Register a scheduled cron task
Metadata
| Field | Value |
|---|---|
| Article type | Hook Reference |
| Plugin slug | mam-main |
| Applies to plugin version | 2.1.11+ |
| Hook type | filter |
| Audience | PHP developer |
| Frozen contract | yes — 25+ subscribers |
| Last verified | 2026-05-02 |
