Introduction
WordPress uses a pseudo-cron system called wp-cron to handle scheduled tasks like publishing scheduled posts, checking for updates, sending email notifications, and running plugin background processes. Unlike traditional system cron that runs at fixed intervals, wp-cron only executes when a page is loaded on the site. This design can fail when the DISABLE_WP_CRON constant is set, when sites have low traffic, when wp-cron.php is blocked by security plugins, or when PHP timeouts prevent completion. Understanding how WordPress cron works and configuring proper alternatives is essential for reliable scheduled task execution.
Symptoms
When WordPress cron is not running, you will observe:
- Scheduled posts miss their publish time and remain in "Scheduled" status
- Plugin updates and WordPress core updates not running automatically
- Backup plugins not executing scheduled backups
- Email notifications from forms or plugins not sending
- WooCommerce order status updates not processing
- SEO plugins not generating sitemaps automatically
- Transients and scheduled cleanup tasks not running
WordPress admin dashboard may show: - "Missed schedule" badge on posts - Pending plugin updates showing for days - Backups showing "Last run: Never" or old dates
Test by checking cron status: ```bash # Check if scheduled posts are missed wp post list --post_status=future --format=count
# List scheduled cron events wp cron event list --fields=hook,next_run
# Check if cron is disabled grep -r "DISABLE_WP_CRON" wp-config.php ```
Common Causes
- 1.DISABLE_WP_CRON constant set - wp-cron disabled in wp-config.php without alternative
- 2.Low site traffic - No visitors to trigger wp-cron execution
- 3.wp-cron.php blocked - Security plugin or firewall blocking requests
- 4.PHP timeout - Long-running cron tasks exceeding execution time
- 5.Memory limit exceeded - Cron processes running out of memory
- 6.Missed cron events - Events stuck in "missed" state
- 7.Plugin conflicts - Multiple plugins scheduling duplicate events
- 8.Database issues - Cron options table corruption
- 9.Server clock drift - Server time incorrect causing scheduling issues
- 10.Cache interference - Page caching preventing wp-cron triggers
Step-by-Step Fix
Step 1: Diagnose Cron Status
Check if WordPress cron is disabled and what events are scheduled:
```bash # Check wp-config.php for DISABLE_WP_CRON grep -i "DISABLE_WP_CRON" wp-config.php
# List all scheduled cron events wp cron event list --format=table --fields=hook,next_run,status
# Check cron option in database wp option get cron --format=json
# Test cron manually wp cron event run --due-now ```
If DISABLE_WP_CRON is true:
``php
// In wp-config.php, look for:
define('DISABLE_WP_CRON', true);
This disables automatic cron execution on page loads.
Step 2: Test wp-cron.php Manually
Test if wp-cron.php is accessible and executing:
```bash # Test wp-cron directly via HTTP curl -v https://yourdomain.com/wp-cron.php?doing_wp_cron
# Check response code curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/wp-cron.php
# Test from server locally curl -s http://localhost/wp-cron.php?doing_wp_cron
# Check if blocked by .htaccess cat .htaccess | grep -i cron ```
Common .htaccess block:
``apache
# This blocks wp-cron.php
<FilesMatch "wp-cron\.php">
Order Allow,Deny
Deny from all
</FilesMatch>
Remove or modify this to allow access.
Step 3: Check for Missed Scheduled Events
Find and process missed cron events:
```bash # List missed events wp cron event list --status=missed --fields=hook,next_run
# Run all missed events wp cron event run --status=missed
# Run specific missed event wp cron event run publish_future_post_123
# Clear all missed events (use carefully) wp eval "delete_transient('doing_cron');" ```
Using WP-CLI to repair scheduled posts: ```bash # Find scheduled posts that should have published wp post list --post_status=future --before="now" --fields=ID,post_title,post_date
# Publish missed scheduled posts wp post update $(wp post list --post_status=future --before="now" --format=ids) --post_status=publish
# Or use the "Cron Control" plugin to manage events wp cron-control event list ```
Step 4: Configure System Cron (Recommended)
Replace wp-cron with a real system cron job:
Step 4a: Disable wp-cron in wp-config.php:
``php
// Add to wp-config.php (near other defines)
define('DISABLE_WP_CRON', true);
Step 4b: Create system cron job: ```bash # Edit crontab for web server user crontab -e -u www-data
# Add cron entry (runs every 5 minutes) */5 * * * * curl -s -o /dev/null https://yourdomain.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
# Alternative using WP-CLI (recommended for better performance) */5 * * * * /usr/local/bin/wp cron event run --due-now --path=/var/www/html > /dev/null 2>&1
# For multisite, run for each site */5 * * * * /usr/local/bin/wp cron event run --due-now --url=site1.example.com --path=/var/www/html > /dev/null 2>&1 ```
Step 4c: Verify cron is running: ```bash # Check crontab is installed crontab -l -u www-data
# Monitor cron execution tail -f /var/log/syslog | grep CRON
# Test manually first /usr/local/bin/wp cron event run --due-now --path=/var/www/html ```
Step 5: Increase PHP Resources for Cron
Cron tasks may fail due to resource limits:
```bash # Edit wp-config.php to increase limits for cron define('WP_MEMORY_LIMIT', '256M'); define('WP_MAX_MEMORY_LIMIT', '512M');
# Or create a custom php.ini for cron cat > /var/www/html/.user.ini << 'EOF' memory_limit = 512M max_execution_time = 300 EOF ```
If using WP-CLI for cron, ensure it uses correct PHP: ```bash # Check WP-CLI PHP version wp --info | grep "PHP version"
# If needed, specify PHP binary in crontab */5 * * * * /usr/bin/php8.1 /usr/local/bin/wp cron event run --due-now --path=/var/www/html ```
Step 6: Clear Stuck Cron Locks
If cron appears stuck, clear the lock:
```bash # Clear doing_cron transient wp transient delete doing_cron
# Check for locked cron processes wp option get doing_cron
# Clear via database directly mysql -u wordpress -p wordpress -e "DELETE FROM wp_options WHERE option_name = 'doing_cron';"
# Clear cron option and reschedule wp eval " delete_option('cron'); wp_schedule_event(time(), 'hourly', 'wp_scheduled_delete'); wp_schedule_event(time(), 'daily', 'wp_scheduled_auto_draft_delete'); " ```
Step 7: Fix Plugin Conflicts
Identify and resolve plugin-related cron issues:
```bash # List all cron hooks and their origins wp cron event list --fields=hook,arguments,next_run --format=csv
# Find which plugin registered a hook grep -r "wp_schedule_event|wp_schedule_single_event" wp-content/plugins/
# Check for duplicate events wp cron event list --fields=hook | sort | uniq -c | sort -rn | head
# Disable specific plugin's cron # Example: Disable broken backup plugin cron wp cron event delete wp_backup_plugin_schedule ```
Step 8: Repair Database Cron Option
If cron data is corrupted:
```bash # Backup cron data first wp option get cron --format=json > cron-backup.json
# Check cron option integrity wp eval "var_dump(unserialize(get_option('cron')));"
# If corrupted, repair wp eval " \$cron = get_option('cron'); if (!is_array(\$cron)) { delete_option('cron'); _set_cron_array(array()); } "
# Repair database tables wp db repair ```
Verification
After making changes, verify cron is working:
```bash # Test immediate cron execution wp cron event run --due-now
# Check upcoming scheduled events wp cron event list --fields=hook,next_run --status=pending
# Verify system cron is running grep CRON /var/log/syslog | tail -5
# Test with a scheduled post # Create a post scheduled for 2 minutes from now, verify it publishes ```
Test scheduled post publishing: ```bash # Create test scheduled post wp post create --post_title="Test Scheduled Post" \ --post_content="This is a test" \ --post_status=future \ --post_date="$(date -d '+2 minutes' '+%Y-%m-%d %H:%M:%S')"
# Wait 3 minutes, then check wp post list --name=test-scheduled-post --fields=post_status # Expected: post_status=publish ```
Monitor cron execution: ```bash # Watch cron events being processed watch -n 5 'wp cron event list --fields=hook,next_run,status --due-now'
# Check wp-cron.php response curl -w "\nTime: %{time_total}s\n" https://yourdomain.com/wp-cron.php?doing_wp_cron ```
Prevention
To prevent future cron issues:
- 1.Use system cron instead of wp-cron:
- 2.```bash
- 3.# Set up proper system cron
- 4.crontab -l -u www-data
- 5.# Should show the wp-cron alternative
- 6.
` - 7.Monitor scheduled tasks:
- 8.```bash
- 9.# Add to monitoring script
- 10.wp cron event list --status=missed --format=count
- 11.# Alert if count > 0
- 12.
` - 13.Schedule cron at appropriate intervals:
- 14.```bash
- 15.# For high-traffic sites: every 15 minutes
- 16.*/15 * * * * wp cron event run --due-now --path=/var/www/html
# For low-traffic sites: every minute * * * * * wp cron event run --due-now --path=/var/www/html ```
- 1.Use WP Control plugin for visibility:
- 2.- Install "WP Crontrol" plugin to view and manage cron events
- 3.- Provides dashboard visibility of all scheduled tasks
- 4.Implement cron health check:
- 5.```php
- 6.// Add to functions.php
- 7.add_action('wp', function() {
- 8.$last_cron = get_transient('last_cron_run');
- 9.if (!$last_cron || $last_cron < time() - 3600) {
- 10.// No cron in last hour - might be broken
- 11.error_log('WordPress cron may not be running');
- 12.}
- 13.});
add_action('wp_cron_health_check', function() { set_transient('last_cron_run', time(), DAY_IN_SECONDS); });
// Schedule health check if (!wp_next_scheduled('wp_cron_health_check')) { wp_schedule_event(time(), 'hourly', 'wp_cron_health_check'); } ```
- 1.Set up alerts for missed scheduled posts:
- 2.```bash
- 3.# Cron job to check for missed scheduled posts
- 4.0 * * * * /usr/local/bin/wp post list --post_status=future --before="1 hour ago" --format=count --path=/var/www/html | xargs -I {} test {} -gt 0 && echo "Alert: Missed scheduled posts" | mail -s "WordPress Alert" admin@example.com
- 5.
` - 6.Document your cron setup:
- 7.```bash
- 8.# Create documentation file
- 9.cat > /var/www/html/CRON-SETUP.md << 'EOF'
- 10.# WordPress Cron Configuration
- System cron runs every 5 minutes via crontab
- - DISABLE_WP_CRON is true
- - WP-CLI handles execution: wp cron event run --due-now
- - Logs available in: /var/log/wp-cron.log
- EOF
`
Related Articles
- [WordPress troubleshooting: Fix Child Theme Not Enqueuing Parent Styles Correc](child-theme-not-enqueuing-parent-styles-correctly)
- [Fix Database Connection Error Custom Socket Path Issue in WordPress](database-connection-error-custom-socket-path)
- [Fix Debug Log Growing Deprecated Warnings Notices Issue in WordPress](debug-log-growing-deprecated-warnings-notices)
- [Fix Fix Contact Form Not Sending On Wordpress Site Issue in WordPress](fix-contact-form-not-sending-on-wordpress-site)
- [Fix Fix Open Basedir Restriction Blocking Wordpress Issue in WordPress](fix-open-basedir-restriction-blocking-wordpress)
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "WordPress Cron Not Running", "description": "Fix WordPress cron jobs not running. Troubleshoot wp-cron.php issues, configure system cron, and ensure scheduled tasks execute.", "url": "https://www.fixwikihub.com/fix-wordpress-cron-job-not-running", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2025-12-12T19:22:32.445Z", "dateModified": "2025-12-12T19:22:32.445Z" } </script>