Skip to content

Instantly share code, notes, and snippets.

@galinio
Created March 9, 2026 14:10
Show Gist options
  • Select an option

  • Save galinio/03bfc83a50d19b2cb3fb94434b27f937 to your computer and use it in GitHub Desktop.

Select an option

Save galinio/03bfc83a50d19b2cb3fb94434b27f937 to your computer and use it in GitHub Desktop.
WordPress cleanup script - remove unused tags, close comments, delete spam, export 404 URLs (WP-CLI)
#!/bin/bash
# ============================================================
# WordPress Site Cleanup Script
# Run this on your WordPress server to:
# 1. Backup and remove unused tags
# 2. Close comments on all posts and pages
# 3. Disable pingbacks
# 4. Delete spam comments
# 5. Export 404 URLs from Apache logs
# ============================================================
set -e
# ------- CONFIGURATION (edit these) -------
WP_PATH="/opt/bitnami/wordpress"
BACKUP_DIR="/tmp/wp-cleanup-$(date +%Y%m%d)"
LOG_DIR="/opt/bitnami/apache/logs"
CONTENT_PATHS="^/(blog|topics|tutorials|devops)"
# ------------------------------------------
WP="sudo wp --path=$WP_PATH --allow-root"
mkdir -p "$BACKUP_DIR"
echo ""
echo "============================================"
echo " WordPress Cleanup Script"
echo " Backup directory: $BACKUP_DIR"
echo "============================================"
echo ""
# --------------------------------------------------
# STEP 1: Backup and remove unused tags
# --------------------------------------------------
echo "[1/5] Backing up all tags..."
$WP term list post_tag --fields=term_id,name,slug,count --format=csv > "$BACKUP_DIR/tags-backup.csv" 2>/dev/null
TAG_TOTAL=$(tail -n +2 "$BACKUP_DIR/tags-backup.csv" | wc -l)
echo " Saved $TAG_TOTAL tags to $BACKUP_DIR/tags-backup.csv"
echo ""
echo "[1/5] Finding unused tags (count = 0)..."
UNUSED_IDS=$(awk -F"," 'NR>1 && $NF==0 {print $1}' "$BACKUP_DIR/tags-backup.csv")
UNUSED_COUNT=$(echo "$UNUSED_IDS" | grep -c . || true)
if [ "$UNUSED_COUNT" -gt 0 ]; then
echo " Found $UNUSED_COUNT unused tags. Deleting..."
for id in $UNUSED_IDS; do
$WP term delete post_tag "$id" 2>/dev/null
done
echo " Deleted $UNUSED_COUNT unused tags."
else
echo " No unused tags found. Skipping."
fi
# --------------------------------------------------
# STEP 2: Close comments on all posts and pages
# --------------------------------------------------
echo ""
echo "[2/5] Closing comments on all posts..."
OPEN_POSTS=$($WP post list --post_type=post --comment_status=open --fields=ID --format=ids 2>/dev/null || true)
if [ -n "$OPEN_POSTS" ]; then
echo "$OPEN_POSTS" | xargs $WP post update --comment_status=closed 2>/dev/null
POST_COUNT=$(echo "$OPEN_POSTS" | wc -w)
echo " Closed comments on $POST_COUNT posts."
else
echo " All posts already have comments closed."
fi
echo ""
echo "[2/5] Closing comments on all pages..."
OPEN_PAGES=$($WP post list --post_type=page --comment_status=open --fields=ID --format=ids 2>/dev/null || true)
if [ -n "$OPEN_PAGES" ]; then
echo "$OPEN_PAGES" | xargs $WP post update --comment_status=closed 2>/dev/null
PAGE_COUNT=$(echo "$OPEN_PAGES" | wc -w)
echo " Closed comments on $PAGE_COUNT pages."
else
echo " All pages already have comments closed."
fi
# --------------------------------------------------
# STEP 3: Set default comment and ping status
# --------------------------------------------------
echo ""
echo "[3/5] Setting default comment status to closed..."
$WP option update default_comment_status closed 2>/dev/null
echo " Done."
echo ""
echo "[3/5] Disabling pingbacks..."
$WP option update default_ping_status closed 2>/dev/null
echo " Done."
# --------------------------------------------------
# STEP 4: Delete spam comments
# --------------------------------------------------
echo ""
echo "[4/5] Checking for spam comments..."
SPAM_IDS=$($WP comment list --status=spam --fields=comment_ID --format=ids 2>/dev/null || true)
if [ -n "$SPAM_IDS" ]; then
# Backup spam before deleting
$WP comment list --status=spam --fields=comment_ID,comment_author,comment_author_email,comment_date --format=csv > "$BACKUP_DIR/spam-comments-backup.csv" 2>/dev/null
SPAM_COUNT=$(echo "$SPAM_IDS" | wc -w)
echo " Found $SPAM_COUNT spam comments. Backed up to $BACKUP_DIR/spam-comments-backup.csv"
echo " Deleting spam..."
echo "$SPAM_IDS" | xargs $WP comment delete --force 2>/dev/null
echo " Deleted $SPAM_COUNT spam comments."
else
echo " No spam comments found."
fi
# Show approved comments count (untouched)
APPROVED=$($WP comment count 2>/dev/null | grep -A1 approved | tail -1 | tr -d ' ' || echo "0")
echo " Approved comments (untouched): $APPROVED"
# --------------------------------------------------
# STEP 5: Export 404 URLs from Apache logs
# --------------------------------------------------
echo ""
echo "[5/5] Scanning Apache logs for 404 content URLs..."
{
sudo grep ' 404 ' "$LOG_DIR/access_log" 2>/dev/null | awk '{print $7}'
sudo zgrep ' 404 ' "$LOG_DIR/access_log"*.gz 2>/dev/null | awk -F'"' '{print $2}' | awk '{print $2}'
} | grep -E "$CONTENT_PATHS" | sort | uniq -c | sort -rn > "$BACKUP_DIR/404-urls.txt" 2>/dev/null || true
URL_COUNT=$(wc -l < "$BACKUP_DIR/404-urls.txt" 2>/dev/null || echo "0")
echo " Found $URL_COUNT unique 404 content URLs."
echo " Saved to $BACKUP_DIR/404-urls.txt"
if [ "$URL_COUNT" -gt 0 ]; then
echo ""
echo " Top 10 most-hit 404 URLs:"
head -10 "$BACKUP_DIR/404-urls.txt" | while read count url; do
printf " %6s hits %s\n" "$count" "$url"
done
fi
# --------------------------------------------------
# SUMMARY
# --------------------------------------------------
echo ""
echo "============================================"
echo " Cleanup Complete"
echo "============================================"
echo ""
echo " Tags backup: $BACKUP_DIR/tags-backup.csv"
echo " Unused tags deleted: ${UNUSED_COUNT:-0}"
echo " Comments closed: all posts and pages"
echo " Pingbacks: disabled"
echo " Spam deleted: ${SPAM_COUNT:-0}"
echo " 404 URLs exported: $BACKUP_DIR/404-urls.txt"
echo ""
echo " NEXT STEP: Review $BACKUP_DIR/404-urls.txt"
echo " and create redirect rules in the Redirection plugin."
echo ""
echo " Approved comments were NOT touched."
echo " All backups saved in: $BACKUP_DIR"
echo ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment