Files
Linux-Server-Management-Too…/modules/website/wordpress-cron-manager.sh
T
cschantz 51d0456805 Add safe wp-config.php modification with validation
Critical Safety Improvements:
- Prevent duplicate DISABLE_WP_CRON entries
- Detect and modify existing definitions (commented or not)
- Automatic rollback on failure
- Verification of changes before committing

Safety Function Features:
 Checks file exists and is writable before modification
 Detects existing DISABLE_WP_CRON (even if set to false)
 Modifies existing line instead of adding duplicate
 Ignores commented lines when detecting existing definitions
 Creates temporary backup (.wpbak) during modification
 Verifies change was successful after modification
 Automatically restores backup if verification fails
 Removes temporary backup only on success

Prevents Issues:
 No duplicate define() statements
 No syntax errors from malformed sed commands
 No broken wp-config.php files
 No accumulation of multiple entries on repeated runs

Error Handling:
- Returns 0 on success, 1 on failure
- Calling code can gracefully handle failures
- User feedback when modification fails
- Skips sites that fail instead of breaking entire batch
2025-11-07 17:07:33 -05:00

507 lines
16 KiB
Bash
Executable File

#!/bin/bash
################################################################################
# WordPress Cron Manager
################################################################################
# Purpose: Disable wp-cron and convert to real system cron jobs
# Features:
# - Detect all WordPress installations
# - Disable DISABLE_WP_CRON in wp-config.php
# - Add proper cron jobs for scheduled tasks
# - Server-wide, per-user, or per-domain operations
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$SCRIPT_DIR/lib/common-functions.sh"
source "$SCRIPT_DIR/lib/system-detect.sh"
if [ "$EUID" -ne 0 ]; then
print_error "This script must be run as root"
exit 1
fi
# Global counter for staggering cron times
CRON_OFFSET=0
# Function to generate staggered cron time
# Distributes jobs across 15 minutes to avoid load spikes
generate_staggered_cron() {
local minute=$((CRON_OFFSET % 15))
# Create pattern: 0,15,30,45 but offset by the calculated minute
local minutes=""
for base in 0 15 30 45; do
local actual_minute=$(( (base + minute) % 60 ))
if [ -z "$minutes" ]; then
minutes="$actual_minute"
else
minutes="$minutes,$actual_minute"
fi
done
# Increment offset for next site (wraps at 15)
CRON_OFFSET=$((CRON_OFFSET + 1))
echo "$minutes * * * *"
}
# Function to safely modify wp-config.php to disable wp-cron
# Returns 0 on success, 1 on failure
disable_wpcron_in_config() {
local wp_config="$1"
# Check if file exists and is writable
if [ ! -f "$wp_config" ] || [ ! -w "$wp_config" ]; then
return 1
fi
# Check if DISABLE_WP_CRON already exists (not commented)
if grep -E "^[^/]*define\s*\(\s*['\"]DISABLE_WP_CRON['\"]" "$wp_config" >/dev/null 2>&1; then
# Line exists, modify it to set true
sed -i.wpbak "s/^\([^/]*\)define\s*(\s*['\"]DISABLE_WP_CRON['\"]\s*,\s*[^)]*)/\1define('DISABLE_WP_CRON', true)/" "$wp_config"
else
# Line doesn't exist, add it after <?php
# First, check if <?php exists
if ! grep -q "<?php" "$wp_config"; then
return 1
fi
# Add the define right after <?php, but only if not already present
if ! grep -q "DISABLE_WP_CRON" "$wp_config"; then
sed -i.wpbak "/<?php/a \\
define('DISABLE_WP_CRON', true);" "$wp_config"
fi
fi
# Verify the change was successful
if grep -E "^[^/]*define\s*\(\s*['\"]DISABLE_WP_CRON['\"]\s*,\s*true\s*\)" "$wp_config" >/dev/null 2>&1; then
# Remove backup if successful
rm -f "${wp_config}.wpbak"
return 0
else
# Restore backup if verification failed
if [ -f "${wp_config}.wpbak" ]; then
mv "${wp_config}.wpbak" "$wp_config"
fi
return 1
fi
}
clear
print_banner "WordPress Cron Manager"
echo ""
echo -e "${BOLD}What would you like to do?${NC}"
echo ""
echo " 1) Scan for WordPress installations"
echo " 2) Disable wp-cron for specific domain"
echo " 3) Disable wp-cron for specific user (all their WP sites)"
echo " 4) Disable wp-cron server-wide (all WordPress sites)"
echo " 5) Check wp-cron status for domain/user"
echo " 0) Return to menu"
echo ""
echo -n "Select option [0]: "
read -r choice
choice="${choice:-0}"
case "$choice" in
1)
# Scan for WordPress installations
echo ""
print_banner "WordPress Installation Scanner"
echo ""
echo "Scanning for WordPress installations..."
echo ""
# Find all wp-config.php files in home directories
wp_sites=$(find /home/*/public_html -name "wp-config.php" -type f 2>/dev/null)
if [ -z "$wp_sites" ]; then
echo -e "${YELLOW}No WordPress installations found${NC}"
else
count=0
echo -e "${BOLD}Found WordPress Installations:${NC}"
echo ""
while IFS= read -r config_file; do
count=$((count + 1))
# Extract info
site_path=$(dirname "$config_file")
user=$(echo "$site_path" | cut -d'/' -f3)
# Try to find domain
domain="(unknown domain)"
if [ -f "/var/cpanel/userdata/$user/main" ]; then
domain=$(grep -m1 "^servername:" "/var/cpanel/userdata/$user/main" 2>/dev/null | awk '{print $2}')
fi
# Check if wp-cron is disabled
if grep -q "define.*DISABLE_WP_CRON.*true" "$config_file" 2>/dev/null; then
status="${GREEN}✓ Disabled (using system cron)${NC}"
else
status="${YELLOW}⚠ Enabled (default wp-cron)${NC}"
fi
echo -e "${count}. ${BOLD}$domain${NC}"
echo " Path: $site_path"
echo " User: $user"
echo " Status: $status"
echo ""
done <<< "$wp_sites"
echo -e "${CYAN}Total WordPress installations: $count${NC}"
fi
;;
2)
# Disable wp-cron for specific domain
echo ""
echo -n "Enter domain name: "
read -r domain
if [ -z "$domain" ]; then
print_error "Domain cannot be empty"
press_enter
exit 1
fi
# Find WordPress installation for this domain
echo ""
echo "Searching for WordPress installation for $domain..."
# Try to find via cPanel user data
wp_config=""
for userdata_file in /var/cpanel/userdata/*/main; do
if grep -q "^servername: $domain" "$userdata_file" 2>/dev/null; then
user=$(basename "$(dirname "$userdata_file")")
potential_config="/home/$user/public_html/wp-config.php"
if [ -f "$potential_config" ]; then
wp_config="$potential_config"
break
fi
fi
done
if [ -z "$wp_config" ]; then
print_error "WordPress installation not found for $domain"
press_enter
exit 1
fi
echo -e "${GREEN}Found WordPress:${NC} $wp_config"
echo ""
# Check if already disabled
if grep -q "define.*DISABLE_WP_CRON.*true" "$wp_config" 2>/dev/null; then
echo -e "${YELLOW}wp-cron is already disabled for this site${NC}"
echo ""
echo -n "Re-configure anyway? (y/n) [n]: "
read -r confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
press_enter
exit 0
fi
fi
# Backup wp-config.php
cp "$wp_config" "${wp_config}.backup-$(date +%Y%m%d-%H%M%S)"
echo -e "${GREEN}${NC} Backed up wp-config.php"
# Safely disable wp-cron in wp-config.php
if disable_wpcron_in_config "$wp_config"; then
echo -e "${GREEN}${NC} Set DISABLE_WP_CRON to true in wp-config.php"
else
print_error "Failed to modify wp-config.php"
echo " Please check file permissions and syntax"
press_enter
exit 1
fi
# Add cron job with staggered timing
site_path=$(dirname "$wp_config")
cron_cmd="cd $site_path && /usr/bin/php -q wp-cron.php >/dev/null 2>&1"
# Add to user's crontab
user=$(echo "$site_path" | cut -d'/' -f3)
# Check if cron job already exists
if crontab -u "$user" -l 2>/dev/null | grep -q "$site_path.*wp-cron.php"; then
echo -e "${YELLOW}${NC} Cron job already exists for this site"
else
# Generate staggered cron time
cron_time=$(generate_staggered_cron)
(crontab -u "$user" -l 2>/dev/null; echo "$cron_time $cron_cmd") | crontab -u "$user" -
echo -e "${GREEN}${NC} Added cron job ($cron_time)"
fi
echo ""
print_success "WordPress cron converted to system cron for $domain"
echo ""
echo "Changes made:"
echo " • DISABLE_WP_CRON set to true in wp-config.php"
echo " • System cron job added (every 15 minutes)"
echo " • Backup saved: ${wp_config}.backup-*"
;;
3)
# Disable wp-cron for specific user
echo ""
echo -n "Enter cPanel username: "
read -r target_user
if [ -z "$target_user" ]; then
print_error "Username cannot be empty"
press_enter
exit 1
fi
if [ ! -d "/home/$target_user" ]; then
print_error "User $target_user does not exist"
press_enter
exit 1
fi
echo ""
echo "Searching for WordPress installations for user: $target_user"
echo ""
wp_configs=$(find "/home/$target_user" -name "wp-config.php" -type f 2>/dev/null)
if [ -z "$wp_configs" ]; then
print_error "No WordPress installations found for $target_user"
press_enter
exit 1
fi
count=0
echo "$wp_configs" | while IFS= read -r wp_config; do
count=$((count + 1))
site_path=$(dirname "$wp_config")
echo -e "${BOLD}Site $count:${NC} $site_path"
# Backup
cp "$wp_config" "${wp_config}.backup-$(date +%Y%m%d-%H%M%S)" 2>/dev/null
echo " • Backed up wp-config.php"
# Safely disable wp-cron
if disable_wpcron_in_config "$wp_config"; then
echo " • Set DISABLE_WP_CRON to true"
else
echo "${YELLOW}Warning: Could not modify wp-config.php${NC}"
echo ""
continue
fi
# Add cron job with staggered timing
cron_cmd="cd $site_path && /usr/bin/php -q wp-cron.php >/dev/null 2>&1"
if ! crontab -u "$target_user" -l 2>/dev/null | grep -q "$site_path.*wp-cron.php"; then
cron_time=$(generate_staggered_cron)
(crontab -u "$target_user" -l 2>/dev/null; echo "$cron_time $cron_cmd") | crontab -u "$target_user" -
echo " • Added cron job ($cron_time)"
else
echo " • Cron job already exists"
fi
echo ""
done
print_success "All WordPress sites for $target_user converted to system cron"
;;
4)
# Server-wide conversion
echo ""
echo -e "${RED}${BOLD}WARNING: Server-Wide wp-cron Conversion${NC}"
echo ""
echo "This will:"
echo " • Find ALL WordPress installations on the server"
echo " • Disable wp-cron in each wp-config.php"
echo " • Add system cron jobs for each user"
echo ""
echo -n "Are you sure? Type 'yes' to confirm: "
read -r confirm
if [ "$confirm" != "yes" ]; then
echo "Cancelled"
press_enter
exit 0
fi
echo ""
echo "Scanning entire server for WordPress installations..."
echo ""
total=0
converted=0
wp_configs=$(find /home/*/public_html -name "wp-config.php" -type f 2>/dev/null)
if [ -z "$wp_configs" ]; then
echo -e "${YELLOW}No WordPress installations found${NC}"
press_enter
exit 0
fi
while IFS= read -r wp_config; do
total=$((total + 1))
site_path=$(dirname "$wp_config")
user=$(echo "$site_path" | cut -d'/' -f3)
echo -e "${BOLD}Processing:${NC} $site_path (user: $user)"
# Backup
cp "$wp_config" "${wp_config}.backup-$(date +%Y%m%d-%H%M%S)" 2>/dev/null
# Safely disable wp-cron
if ! disable_wpcron_in_config "$wp_config"; then
echo -e "${YELLOW}⚠ Failed to modify wp-config.php${NC}"
echo ""
continue
fi
# Add cron job with staggered timing
cron_cmd="cd $site_path && /usr/bin/php -q wp-cron.php >/dev/null 2>&1"
if ! crontab -u "$user" -l 2>/dev/null | grep -q "$site_path.*wp-cron.php"; then
cron_time=$(generate_staggered_cron)
(crontab -u "$user" -l 2>/dev/null; echo "$cron_time $cron_cmd") | crontab -u "$user" - 2>/dev/null
echo " Cron: $cron_time"
fi
converted=$((converted + 1))
echo -e "${GREEN}${NC} Converted"
echo ""
done <<< "$wp_configs"
echo ""
print_success "Server-wide conversion complete"
echo ""
echo "Summary:"
echo " • Total WordPress sites found: $total"
echo " • Successfully converted: $converted"
;;
5)
# Check status
echo ""
echo "Check wp-cron status for:"
echo " 1) Specific domain"
echo " 2) Specific user"
echo ""
echo -n "Select [1]: "
read -r check_choice
check_choice="${check_choice:-1}"
if [ "$check_choice" = "1" ]; then
echo ""
echo -n "Enter domain name: "
read -r domain
# Find WordPress for domain
wp_config=""
for userdata_file in /var/cpanel/userdata/*/main; do
if grep -q "^servername: $domain" "$userdata_file" 2>/dev/null; then
user=$(basename "$(dirname "$userdata_file")")
potential_config="/home/$user/public_html/wp-config.php"
if [ -f "$potential_config" ]; then
wp_config="$potential_config"
break
fi
fi
done
if [ -z "$wp_config" ]; then
print_error "WordPress not found for $domain"
press_enter
exit 1
fi
echo ""
echo -e "${BOLD}WordPress Cron Status for $domain${NC}"
echo ""
echo "Config file: $wp_config"
echo ""
if grep -q "define.*DISABLE_WP_CRON.*true" "$wp_config" 2>/dev/null; then
echo -e "wp-cron: ${GREEN}DISABLED${NC} (using system cron)"
# Check for cron job
site_path=$(dirname "$wp_config")
user=$(echo "$site_path" | cut -d'/' -f3)
if crontab -u "$user" -l 2>/dev/null | grep -q "wp-cron.php"; then
echo -e "System cron: ${GREEN}CONFIGURED${NC}"
echo ""
echo "Cron jobs:"
crontab -u "$user" -l 2>/dev/null | grep "wp-cron.php"
else
echo -e "System cron: ${RED}NOT CONFIGURED${NC}"
fi
else
echo -e "wp-cron: ${YELLOW}ENABLED${NC} (default WordPress cron)"
echo ""
echo "Recommendation: Disable wp-cron and use system cron for better performance"
fi
else
echo ""
echo -n "Enter cPanel username: "
read -r check_user
if [ ! -d "/home/$check_user" ]; then
print_error "User $check_user does not exist"
press_enter
exit 1
fi
echo ""
echo -e "${BOLD}WordPress Cron Status for user: $check_user${NC}"
echo ""
wp_configs=$(find "/home/$check_user" -name "wp-config.php" -type f 2>/dev/null)
if [ -z "$wp_configs" ]; then
echo "No WordPress installations found"
else
count=0
while IFS= read -r wp_config; do
count=$((count + 1))
site_path=$(dirname "$wp_config")
echo -e "${count}. ${BOLD}$site_path${NC}"
if grep -q "define.*DISABLE_WP_CRON.*true" "$wp_config" 2>/dev/null; then
echo " wp-cron: ${GREEN}DISABLED${NC}"
else
echo " wp-cron: ${YELLOW}ENABLED${NC}"
fi
echo ""
done <<< "$wp_configs"
# Show cron jobs
echo -e "${BOLD}Cron Jobs:${NC}"
if crontab -u "$check_user" -l 2>/dev/null | grep -q "wp-cron.php"; then
crontab -u "$check_user" -l 2>/dev/null | grep "wp-cron.php"
else
echo " No wp-cron jobs found"
fi
fi
fi
;;
0)
exit 0
;;
*)
print_error "Invalid option"
;;
esac
echo ""
press_enter