How to Schedule WP-CLI Tasks with Cron: Complete Automation Guide

Automating WordPress maintenance tasks saves time, reduces human error, and ensures critical operations run consistently. By combining WP-CLI with cron jobs, you can create a robust automation system that handles backups, updates, cleanup, and monitoring without manual intervention.

Understanding Cron and WP-CLI Integration

Cron is a time-based job scheduler in Unix-like operating systems that executes commands at specified intervals. When paired with WP-CLI, cron enables you to automate virtually any WordPress operation, from database optimization to content publishing.

The combination offers powerful capabilities: scheduled backups during off-peak hours, automatic plugin updates with rollback protection, regular security scans, database cleanup operations, and automated content workflows. This automation frees developers to focus on building features rather than routine maintenance.

Crontab Syntax Essentials

Understanding cron syntax is fundamental to creating effective scheduled tasks. A cron expression consists of five time fields followed by the command to execute:

* * * * * command-to-execute
│ │ │ │ │
│ │ │ │ └─── Day of week (0-7, where 0 and 7 are Sunday)
│ │ │ └───── Month (1-12)
│ │ └─────── Day of month (1-31)
│ └───────── Hour (0-23)
└─────────── Minute (0-59)

Common patterns include:

  • 0 2 * * * – Daily at 2:00 AM
  • */15 * * * * – Every 15 minutes
  • 0 0 * * 0 – Weekly on Sunday at midnight
  • 0 3 1 * * – Monthly on the 1st at 3:00 AM
  • 0 */6 * * * – Every 6 hours

Special strings provide shortcuts: @reboot (on system startup), @daily (once per day), @hourly (once per hour), @weekly (once per week), and @monthly (once per month).

Setting Up Your First WP-CLI Cron Job

Begin by accessing your crontab editor with crontab -e. For a simple daily backup task:

# Daily WordPress database backup at 2 AM
0 2 * * * /usr/local/bin/wp --path=/var/www/html db export /backups/db-$(date +\%Y\%m\%d).sql --allow-root

Critical considerations when writing cron jobs: always use absolute paths for commands and files, set the correct user permissions, escape special characters (like % with backslash), and specify the WordPress path with the --path flag.

If WP-CLI runs as root, include the --allow-root flag. However, running as the web server user (like www-data) is generally safer:

# Run as www-data user
0 2 * * * sudo -u www-data /usr/local/bin/wp --path=/var/www/html db export /backups/db-$(date +\%Y\%m\%d).sql

Creating a Maintenance Script

Rather than cramming complex logic into crontab, create dedicated scripts that cron executes. This approach improves maintainability, enables version control, and facilitates testing.

#!/bin/bash
# /opt/scripts/wp-maintenance.sh
# WordPress daily maintenance automation

set -euo pipefail

WP_PATH="/var/www/html"
BACKUP_DIR="/backups/wordpress"
LOG_FILE="/var/log/wp-maintenance.log"
DATE=$(date +%Y%m%d-%H%M%S)

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

log "Starting WordPress maintenance"

# Create backup directory if it doesn't exist
mkdir -p "$BACKUP_DIR"

# Database backup
log "Creating database backup"
wp --path="$WP_PATH" db export "$BACKUP_DIR/database-$DATE.sql" || {
    log "ERROR: Database backup failed"
    exit 1
}

# Optimize database
log "Optimizing database"
wp --path="$WP_PATH" db optimize

# Clean up old backups (keep last 7 days)
log "Cleaning old backups"
find "$BACKUP_DIR" -name "database-*.sql" -mtime +7 -delete

# Update plugins (excluding specific ones)
log "Updating plugins"
wp --path="$WP_PATH" plugin update --all --exclude=woocommerce,elementor

# Clear transients
log "Clearing expired transients"
wp --path="$WP_PATH" transient delete --expired

# Generate thumbnail for recent uploads
log "Regenerating recent thumbnails"
wp --path="$WP_PATH" media regenerate --yes --only-missing

# Clear object cache if available
if wp --path="$WP_PATH" cache flush &>/dev/null; then
    log "Cache flushed successfully"
fi

log "Maintenance completed successfully"

Make the script executable and add to crontab:

chmod +x /opt/scripts/wp-maintenance.sh

# In crontab
0 3 * * * /opt/scripts/wp-maintenance.sh

Advanced Scheduling Strategies

Complex WordPress operations often require conditional logic, environment-specific configurations, and coordination between multiple tasks.

#!/bin/bash
# Advanced scheduling with environment detection

WP_PATH="/var/www/html"

# Detect environment
ENVIRONMENT=$(wp --path="$WP_PATH" config get WP_ENVIRONMENT_TYPE)

case $ENVIRONMENT in
    production)
        # Conservative updates in production
        wp --path="$WP_PATH" plugin update --minor
        wp --path="$WP_PATH" core update --minor
        ;;
    staging)
        # More aggressive updates in staging
        wp --path="$WP_PATH" plugin update --all
        wp --path="$WP_PATH" core update
        wp --path="$WP_PATH" theme update --all
        ;;
    development)
        # Full updates including development versions
        wp --path="$WP_PATH" plugin update --all
        wp --path="$WP_PATH" core update --version=nightly
        ;;
esac

For coordinated tasks across multiple sites:

#!/bin/bash
# Multi-site update coordination

SITES=(
    "/var/www/site1"
    "/var/www/site2"
    "/var/www/site3"
)

for site in "${SITES[@]}"; do
    echo "Processing: $site"

    # Check if site is healthy before updating
    if wp --path="$site" core is-installed; then
        wp --path="$site" core update --minor
        wp --path="$site" plugin update --all --exclude=custom-plugin

        # Verify site is still functional
        if ! wp --path="$site" core verify-checksums; then
            echo "WARNING: Checksum verification failed for $site"
            # Send alert notification
        fi
    else
        echo "ERROR: WordPress not properly installed at $site"
    fi
done

Error Handling and Notifications

Production cron jobs require robust error handling and notification systems to alert administrators when problems occur.

#!/bin/bash
# wp-backup-with-notifications.sh

set -euo pipefail

ADMIN_EMAIL="admin@example.com"
WP_PATH="/var/www/html"
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)

send_alert() {
    local subject="$1"
    local message="$2"
    echo "$message" | mail -s "$subject" "$ADMIN_EMAIL"
}

# Trap errors
trap 'send_alert "WordPress Backup Failed" "Backup script failed at line $LINENO"' ERR

# Check disk space
AVAILABLE_SPACE=$(df "$BACKUP_DIR" | tail -1 | awk '{print $4}')
if [ "$AVAILABLE_SPACE" -lt 1048576 ]; then  # Less than 1GB
    send_alert "Low Disk Space Warning" "Available space: ${AVAILABLE_SPACE}KB"
    exit 1
fi

# Perform backup
wp --path="$WP_PATH" db export "$BACKUP_DIR/db-$TIMESTAMP.sql"

# Backup files
tar -czf "$BACKUP_DIR/files-$TIMESTAMP.tar.gz" -C "$WP_PATH" wp-content/uploads

# Verify backup integrity
if [ -f "$BACKUP_DIR/db-$TIMESTAMP.sql" ] && [ -f "$BACKUP_DIR/files-$TIMESTAMP.tar.gz" ]; then
    BACKUP_SIZE=$(du -sh "$BACKUP_DIR" | cut -f1)
    send_alert "Backup Completed Successfully" "Backup size: $BACKUP_SIZE"
else
    send_alert "Backup Verification Failed" "One or more backup files are missing"
    exit 1
fi

Logging and Monitoring

Comprehensive logging helps troubleshoot issues and track automation performance over time.

#!/bin/bash
# Enhanced logging example

LOG_DIR="/var/log/wp-automation"
mkdir -p "$LOG_DIR"

# Create dated log file
LOG_FILE="$LOG_DIR/maintenance-$(date +%Y%m%d).log"

# Logging function with levels
log() {
    local level=$1
    shift
    local message="$@"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" >> "$LOG_FILE"
}

# Execute WP-CLI command with logging
wp_execute() {
    local cmd="$@"
    log "INFO" "Executing: wp $cmd"

    if output=$(wp $cmd 2>&1); then
        log "SUCCESS" "Command completed: $output"
        return 0
    else
        log "ERROR" "Command failed: $output"
        return 1
    fi
}

# Usage
wp_execute --path=/var/www/html plugin list --status=active
wp_execute --path=/var/www/html core update --minor

Monitor log files with automated analysis:

# Cron job to analyze logs and send daily summary
0 8 * * * /opt/scripts/analyze-logs.sh

# analyze-logs.sh
#!/bin/bash
LOG_DIR="/var/log/wp-automation"
YESTERDAY=$(date -d "yesterday" +%Y%m%d)
LOG_FILE="$LOG_DIR/maintenance-$YESTERDAY.log"

if [ -f "$LOG_FILE" ]; then
    ERRORS=$(grep -c "\[ERROR\]" "$LOG_FILE" || true)
    SUCCESSES=$(grep -c "\[SUCCESS\]" "$LOG_FILE" || true)

    mail -s "WP Automation Summary $YESTERDAY" admin@example.com <<EOF
Daily WordPress Automation Summary

Successful operations: $SUCCESSES
Failed operations: $ERRORS

Recent errors:
$(grep "\[ERROR\]" "$LOG_FILE" | tail -5)
EOF
fi

Security Considerations

Secure your cron jobs by limiting file permissions, using dedicated service accounts, and protecting sensitive information.

# Create dedicated user for WordPress automation
sudo useradd -r -s /bin/bash wpautomation

# Set appropriate permissions
chmod 700 /opt/scripts/wp-maintenance.sh
chown wpautomation:wpautomation /opt/scripts/wp-maintenance.sh

# Store credentials securely
cat > /home/wpautomation/.wp-cli-credentials << EOF
SMTP_PASSWORD=secure_password
API_KEY=secret_key
EOF

chmod 600 /home/wpautomation/.wp-cli-credentials
chown wpautomation:wpautomation /home/wpautomation/.wp-cli-credentials

# Crontab for wpautomation user
sudo -u wpautomation crontab -e

Testing Cron Jobs

Before deploying to production, test your cron jobs thoroughly:

# Run manually to verify behavior
/opt/scripts/wp-maintenance.sh

# Test with verbose WP-CLI output
wp --path=/var/www/html plugin update --all --dry-run --debug

# Verify cron syntax
# Install cron expression parser
npm install -g cron-validate

# Check if your cron expression is valid
echo "0 3 * * *" | cron-validate

Use temporary increased frequency for testing:

# Test frequency (every 5 minutes)
*/5 * * * * /opt/scripts/test-automation.sh

# Production frequency (daily at 3 AM)
# 0 3 * * * /opt/scripts/wp-maintenance.sh

Best Practices Summary

Always redirect output appropriately – either to log files or use >/dev/null 2>&1 to suppress. Include timeout mechanisms for long-running operations to prevent hanging processes. Implement file locking to prevent concurrent execution when scripts shouldn’t overlap.

Use environment variables for configuration rather than hardcoding values. Document each cron job with comments explaining its purpose and frequency. Regularly review and audit scheduled tasks to remove obsolete jobs.

Consider using cron management tools like whenever (Ruby) or cronitor for monitoring. Set up health checks to verify cron jobs are executing as expected.

Leave a Reply

Your email address will not be published. Required fields are marked *