Writing Handlers

A handler is a PHP file that returns a closure. The closure receives a single argument — an AutomationContext — and runs when any of the automation's triggers fire.

<?php

return function ($ctx) {
    // ... your logic ...

    return ['ok' => true];
};

The handler is stored in its own .php file next to the automation object (an external code field), so it's edited like any code field in the admin but never bloats the collection JSON. It travels with the object through Sync and JumpStart.

The AutomationContext

$ctx is the only thing a handler receives — pre-wired services plus the trigger payload. No need to reach into a container.

Objects

Property What it is
$ctx->objectFetcher Read objects — fetchObject($collection, $id)
$ctx->objectSaver Create objects — saveObject($collection, $data)
$ctx->objectUpdater Update objects — updateObject($collection, $id, $data)
$ctx->objectRemover Delete objects — removeObject($collection, $id)
$ctx->objectCloner Duplicate an object — cloneObject($from, $to)
$ctx->propertyIncrementer Atomic counters — incrementProperty($collection, $id, $property, $amount = 1) / decrementProperty(...)

Deck items (cards/repeaters inside an object)

Property What it is
$ctx->deckItemSaver Add a deck item — saveDeckItem($collection, $objectId, $property, $itemId, $itemData)
$ctx->deckItemUpdater Update a deck item — updateDeckItem(...)
$ctx->deckItemRemover Remove a deck item — removeDeckItem($collection, $objectId, $property, $itemId)
$ctx->deckItemFetcher Read deck items — fetchDeckItem(...), fetchAllDeckItems($collection, $objectId, $property)

Querying

Property What it is
$ctx->indexReader Read a collection index — fetchIndex($collection) (returns a filterable collection)
$ctx->indexSearcher Full-text-ish search — search($collection, $query), searchByProperty($collection, $property, $query)
$ctx->indexQueryService Structured query (filter/sort/paginate) — query($collection, $params)
$ctx->indexBuilder Rebuild an index after batch writes — buildIndex($collection)

Collections & schemas

Property What it is
$ctx->collectionFetcher Inspect a collection — fetchCollection($id), collectionExists($id)
$ctx->schemaFetcher Inspect a schema — fetchSchemaForCollection($collection), schemaExists($id)

Files & images

Property What it is
$ctx->fileSaver Store a file into a file field — save(...)
$ctx->imageSaver Store/process an image into an image field — save(...)

Import & sync

Property What it is
$ctx->csvImporter Import a CSV — import($collection, $file, $updateObject = false)
$ctx->jsonImporter Import JSON — import($collection, $file, $updateObject = false)
$ctx->rssImporter Ingest an RSS feed — import($feedUrl, $collection, $options = [])
$ctx->syncService Push/pull to another T3 install — push(...), pull(...)

Mail, config & run payload

Property What it is
$ctx->mailer Send a Mailer email — sendEmail($mailerId, $data)
$ctx->config Core configuration
$ctx->logger PSR-3 logger writing to jobs.log (channel automations)
$ctx->trigger The trigger row that fired this run (e.g. $ctx->trigger['type'])
$ctx->args Caller inputs — webhook query + body, or manual Run now args
$ctx->event Event payload (collection, id) — event triggers only
$ctx->request The PSR-7 request — webhook triggers only

$ctx->request and $ctx->event are null for schedule runs.

Example: digest email on a schedule

<?php

return function ($ctx) {
    $posts = $ctx->indexReader->fetchIndex('blog')->objects
        ->where('draft', false)
        ->take(5);

    $ctx->mailer->sendEmail('weekly-digest', ['posts' => $posts->all()]);
    $ctx->logger->info('weekly digest sent', ['count' => $posts->count()]);

    return ['sent' => $posts->count()];
};

Return values and errors

  • Return value — whatever the closure returns is recorded on the run record and, for a synchronous webhook, becomes the HTTP response body. Return arrays/scalars (JSON-encodable).
  • Throwing marks the run failed. In development the error surfaces loudly; in production it's contained, optionally emailed via the automation's error mailer, and counts toward auto-disable.

The handler advisory

When you save a handler, the editor scans it for high-risk calls — exec, shell_exec, system, passthru, proc_open, eval, backticks, base64_decode, remote file_get_contents, and similar — and shows a non-blocking advisory listing what it found. It's a heads-up, not a block: many legitimate handlers use these. Review before relying on a handler that reaches for them.