Cron
The cron system lets you define scheduled tasks that run in the background on a
recurring interval. Add a cron.php file to your block directory and Blockstudio
registers the jobs with WordPress Cron, manages their lifecycle, and cleans
them up when the plugin is deactivated.
This is the final piece of the full-stack block pattern: your block can have a
UI (index.twig), server logic (rpc.php), persistent data (db.php), and
now background processing (cron.php).
How it works
- You create
cron.phpin your block directory - It returns an associative array of named jobs
- On each page load, Blockstudio checks if the jobs are scheduled
- Missing schedules are registered with
wp_schedule_event() - WordPress Cron fires the callbacks on the defined interval
- On plugin deactivation, all Blockstudio cron events are unscheduled
blocks/my-block/
├── block.json
├── index.twig
├── rpc.php ← custom endpoints
├── db.php ← data model
├── cron.php ← background tasks
└── style.cssDefining jobs
Return an associative array of jobs. Each job can be a direct callback (defaults
to daily) or an array with schedule and callback:
return [
// Expanded format with custom schedule
'cleanup' => [
'schedule' => 'hourly',
'callback' => function () {
// runs every hour
},
],
// Shorthand: just a callback, defaults to daily
'heartbeat' => function () {
update_option('my_block_last_heartbeat', time());
},
];Schedules
Built-in
WordPress provides these schedules out of the box:
| Schedule | Interval |
|---|---|
hourly | Every hour |
twicedaily | Every 12 hours |
daily | Every 24 hours |
weekly | Every 7 days |
Custom intervals
Register custom intervals via the WordPress cron_schedules filter, then
reference them in cron.php:
add_filter('cron_schedules', function ($schedules) {
$schedules['every_five_minutes'] = [
'interval' => 300,
'display' => 'Every 5 Minutes',
];
$schedules['every_fifteen_minutes'] = [
'interval' => 900,
'display' => 'Every 15 Minutes',
];
return $schedules;
});return [
'check_external_api' => [
'schedule' => 'every_five_minutes',
'callback' => function () { /* ... */ },
],
];Common patterns
Data maintenance
Clean up old records, expire trials, archive inactive entries:
use Blockstudio\Db;
return [
'expire_trials' => [
'schedule' => 'daily',
'callback' => function () {
$db = Db::get('my-theme/app', 'subscribers');
$trials = $db->list(['plan' => 'trial']);
foreach ($trials as $trial) {
if (strtotime($trial['created_at']) < strtotime('-14 days')) {
$db->update((int) $trial['id'], ['plan' => 'expired']);
}
}
},
],
'purge_old_logs' => [
'schedule' => 'weekly',
'callback' => function () {
$db = Db::get('my-theme/app', 'activity_log');
$logs = $db->list();
foreach ($logs as $log) {
if (strtotime($log['created_at']) < strtotime('-90 days')) {
$db->delete((int) $log['id']);
}
}
},
],
];External API sync
Pull data from third-party services on a schedule:
return [
'sync_products' => [
'schedule' => 'hourly',
'callback' => function () {
$response = wp_remote_get('https://api.example.com/products');
if (is_wp_error($response)) {
return;
}
$products = json_decode(wp_remote_retrieve_body($response), true);
$db = \Blockstudio\Db::get('my-theme/shop', 'products');
foreach ($products as $product) {
$existing = $db->list(['external_id' => $product['id']]);
if (empty($existing)) {
$db->create($product);
} else {
$db->update((int) $existing[0]['id'], $product);
}
}
},
],
];Notifications and digests
Send periodic reports or notification emails:
use Blockstudio\Db;
return [
'weekly_digest' => [
'schedule' => 'weekly',
'callback' => function () {
$db = Db::get('my-theme/app', 'subscribers');
$new = count($db->list(['status' => 'active']));
$admin = get_option('admin_email');
wp_mail($admin, 'Weekly Digest', "Active subscribers: $new");
},
],
];Deactivation
All cron events registered by Blockstudio are automatically unscheduled when the plugin is deactivated. This prevents orphaned cron jobs from persisting in the database after the plugin is removed.
Filter
Modify or disable jobs programmatically:
add_filter('blockstudio/cron', function (array $jobs): array {
// Disable a specific job
unset($jobs['my-theme/app']['cleanup']);
// Change a schedule
if (isset($jobs['my-theme/app']['sync'])) {
$jobs['my-theme/app']['sync']['schedule'] = 'twicedaily';
}
return $jobs;
});Debugging
WordPress Cron is triggered by page visits, not by a system-level scheduler.
On low-traffic sites, jobs may not fire exactly on schedule. For reliable timing,
set up a real system cron that hits wp-cron.php:
*/5 * * * * curl -s https://yoursite.com/wp-cron.php > /dev/null 2>&1Then disable WordPress's built-in cron trigger in wp-config.php:
define('DISABLE_WP_CRON', true);To check scheduled events, use WP-CLI:
wp cron event list | grep blockstudio