Cron Jobs & Background Processing in WPDM
WordPress Download Manager 7.0.1 introduces a powerful cron job system for handling background tasks like sending emails, cleaning up expired files, and processing bulk operations. This guide covers everything from basic usage to the developer API.
Overview
The cron job system consists of two main components:
- CronJobs – Scheduler that registers WordPress cron events and handles external triggers
- CronJob – Job manager that dispatches, executes, and tracks individual jobs
Admin Interface
Access the cron jobs settings via Downloads → Settings → Cron Jobs. The interface shows:
- Stats Dashboard – Total, pending, running, completed, and failed job counts
- External Cron URL – URL for triggering job processing from external cron services
- Scheduled Events – WordPress cron events and their next run times
- Recent Jobs – List of recent jobs with status and actions
Job Actions
- Run – Execute a pending job immediately
- Cancel – Cancel a pending job
- Retry – Retry a failed job
- Delete – Remove a job from the queue
Built-in Job Types
1. CleanupJob
Cleans up expired sessions, cache files, and optionally download statistics.
CronJob::dispatch(\WPDM\__\Jobs\CleanupJob::class)
->withData([ 'cleanup_stats' => false, 'note' => 'Scheduled cleanup' ])
->onQueue('maintenance')
->create();
2. DeleteExpiredJob
Moves expired packages to trash based on their expiration date.
CronJob::dispatch(\WPDM\__\Jobs\DeleteExpiredJob::class)
->withData([ 'permanent_delete' => false, 'notify_admin' => true ])
->onQueue('maintenance')
->create();
3. SendEmailJob
Sends emails asynchronously using wp_mail or WPDM Email templates.
CronJob::dispatch(\WPDM\__\Jobs\SendEmailJob::class)
->withData([ 'to' => 'user@example.com', 'subject' => 'Your Download is Ready', 'message' => '<h2>Hello!</h2><p>Your file is ready.</p>', 'template' => 'download-ready' ])
->onQueue('emails')
->create();
Developer API
The CronJob class provides a fluent builder API for dispatching jobs.
Dispatching Jobs
use WPDM\__\CronJob;
// Basic dispatch
$jobId = CronJob::dispatch(MyCustomJob::class)
->withData(['param1' => 'value1'])
->create();
// Full options
$jobId = CronJob::dispatch(MyCustomJob::class)
->withData($payload) // Job data/parameters
->onQueue('my-queue') // Queue name for grouping
->priority(5) // 1-10, higher = sooner
->delay(3600) // Delay in seconds
->attempts(3) // Max retry attempts
->unique('job-key-123') // Prevent duplicates
->create();
Creating Custom Jobs
Create a job class that extends the base Job class:
namespace MyPlugin\Jobs;
use WPDM\__\Jobs\Job;
class ProcessFileJob extends Job
{
/**
* Execute the job
*
* @param object|array $data Job payload
* @return bool Success status
*/
public function handle($data): bool
{
$fileId = $this->get('file_id');
$action = $this->get('action', 'default');
$this->log("Processing file #{$fileId}");
// Your processing logic here
$result = $this->processFile($fileId, $action);
if (!$result) {
$this->log('Processing failed', 'error');
return false;
}
$this->log('File processed successfully');
return true;
}
/**
* Handle job failure
*/
public function failed(\Throwable $e, $data): void
{
parent::failed($e, $data);
// Send admin notification, log to external service, etc.
}
public static function getName(): string
{
return 'Process File';
}
public static function getDescription(): string
{
return 'Processes uploaded files asynchronously';
}
}
Static Methods
// Get job counts by status
$counts = CronJob::getCounts();
// Returns: ['total' => 100, 'pending' => 5, ...]
// Get all jobs with filtering
$jobs = CronJob::getAll([
'limit' => 50,
'status' => 'pending',
'queue' => 'emails',
'orderby' => 'created_at',
'order' => 'DESC',
]);
// Job management
CronJob::retry($jobId); // Retry failed job
CronJob::cancel($jobId); // Cancel pending job
CronJob::delete($jobId); // Delete job
CronJob::cleanup(30); // Delete completed jobs older than 30 days
CronJob::releaseStale(30); // Release locks on stale jobs
Use Cases
1. Async Email Notifications
// Instead of blocking the request
add_action('wpdm_after_download', function($package_id, $user_id) {
CronJob::dispatch(SendEmailJob::class)
->withData([
'to' => get_userdata($user_id)->user_email,
'subject' => 'Thank you for your download',
'message' => 'Your download of ' . get_the_title($package_id) . ' was successful.',
])
->onQueue('emails')
->create();
}, 10, 2);
2. Scheduled Cleanup
// Schedule daily cleanup at midnight
add_action('wpdm_scheduled_tasks', function() {
CronJob::dispatch(CleanupJob::class)
->withData(['cleanup_stats' => false])
->onQueue('maintenance')
->unique('daily_cleanup_' . date('Y-m-d'))
->create();
});
3. Bulk File Processing
// Process multiple files without timeout
function schedule_bulk_processing($file_ids) {
foreach ($file_ids as $index => $file_id) {
CronJob::dispatch(ProcessFileJob::class)
->withData(['file_id' => $file_id])
->onQueue('file-processing')
->delay($index * 5) // Stagger by 5 seconds
->priority(3)
->create();
}
}
External Cron Setup
If DISABLE_WP_CRON is set to true, you need to trigger job processing externally:
Server Crontab
# Run every 5 minutes */5 * * * * curl -s "https://yoursite.com/?wpdm_cron=1&cronkey=YOUR_KEY" > /dev/null 2>&1
Using EasyCron or Similar Service
Copy the External Cron URL from Settings → Cron Jobs and add it to your cron service with a 5-minute interval.
Database Schema
Jobs are stored in the wp_ahm_cron_jobs table:
| Column | Type | Description |
|---|---|---|
| ID | bigint | Auto-increment primary key |
| code | varchar(255) | Unique job identifier |
| type | varchar(255) | Job class name |
| data | longtext | Serialized job payload |
| queue | varchar(100) | Queue name |
| priority | tinyint | 1-10 priority level |
| status | varchar(20) | pending/running/completed/failed |
| attempts | int | Current attempt count |
| max_attempts | int | Maximum retry attempts |
| execute_at | int | Unix timestamp for delayed execution |
| locked_at | int | Lock timestamp (prevents double processing) |
| created_at | datetime | Job creation time |
| updated_at | datetime | Last update time |
Best Practices
- Use queues – Group related jobs (emails, maintenance, processing) for better organization
- Set appropriate priorities – Use higher priority for time-sensitive jobs
- Use unique codes – Prevent duplicate jobs with unique identifiers
- Handle failures gracefully – Implement the
failed()method for error handling - Keep jobs small – Break large tasks into smaller, manageable jobs
- Log important events – Use
$this->log()for debugging and monitoring
Troubleshooting
Jobs Not Running
- Check if
DISABLE_WP_CRONis set – you may need external cron - Verify the
__wpdm_process_jobsevent is scheduled - Check PHP error logs for exceptions
Jobs Stuck in Running
- Use “Run Job Queue Now” button to process stale jobs
- Jobs locked for more than 30 minutes are automatically released
- Check if the job handler is throwing uncaught exceptions
Too Many Failed Jobs
- Review the job data for invalid parameters
- Check external service connectivity (for email jobs)
- Increase max_attempts if failures are transient