Hook: mam_cron_manager

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

  • frequency is minutes, not cron syntax. There is no minute/hour/day-of-week expression — just an interval in minutes plus an optional run_at HHMM 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 to Asia/Kolkata (+05:30) evaluates run_at in IST.
  • Off-set zones (e.g., +05:30) fall back through two timezone_name_from_abbr attempts, then to UTC. Use named timezones where possible.
  • FastCron’s resolution is the real ceiling — if FastCron pings every 5 minutes, a frequency of 1 still 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

  • action must be unique. Two entries sharing an action share the same get_option($action) state row and both dispatch — schedules collide unpredictably.
  • apply_filters not do_action. The callback is invoked as apply_filters($action, array()) and its returned array is read back for last_run / next_run, so always return an array.
  • No retry semantics. A failed cron callback isn’t retried until its next_run comes 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.

  • 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
Was this article helpful?
Contents

    Need Support?

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