If you’ve been running a WordPress blog for a while, things pile up. Unused tags, old URLs returning 404, spam comments sneaking through, and comment forms still open on posts you forgot about. You can fix all of this from the command line using WP-CLI without touching the WordPress admin panel.
This guide covers the full cleanup process I ran on my own site. The examples are run on WSL2 Ubuntu in Windows over SSH to a Bitnami WordPress server, but they work the same on any Ubuntu system with WP-CLI installed.
Prerequisites
- SSH access to your WordPress server
- WP-CLI installed on the server (Bitnami stacks include it by default)
- A backup of your database before making changes
- The Redirection plugin (for importing redirect rules)
Find and Remove Unused Tags
Over time, you end up with tags that aren’t assigned to any post. These clutter your tag archive pages and add noise to your sitemap. Here’s how to find them.
List All Tags with Post Counts
sudo wp --path=/opt/bitnami/wordpress --allow-root term list post_tag --fields=term_id,name,slug,count --format=table
This prints every tag with how many posts use it. Look for tags where count is 0 — those are unused.
Backup Tags Before Deleting
Always export before deleting anything. Save all tags to a CSV file first.
sudo wp --path=/opt/bitnami/wordpress --allow-root term list post_tag --fields=term_id,name,slug,count --format=csv > /tmp/tags-backup.csv
Get Unused Tag IDs
sudo wp --path=/opt/bitnami/wordpress --allow-root term list post_tag --fields=term_id,count --format=csv | awk -F"," 'NR>1 && $2==0 {print $1}'
This filters the CSV output to only show term IDs where the count is zero.
Delete Unused Tags
Once you have the list, loop through and delete each one.
UNUSED_IDS=$(sudo wp --path=/opt/bitnami/wordpress --allow-root term list post_tag --fields=term_id,count --format=csv | awk -F"," 'NR>1 && $2==0 {print $1}')
for id in $UNUSED_IDS; do
sudo wp --path=/opt/bitnami/wordpress --allow-root term delete post_tag $id
done
On my site, this removed 66 unused tags in one go. You can also check for unused categories using the same approach — just replace post_tag with category.
Disable Comments and Block Spam
If you’ve disabled comments in the WordPress admin but spam is still getting through, the problem is usually that your existing posts still have comments set to “open.” The admin setting only affects new posts.
Check the Default Comment Status
sudo wp --path=/opt/bitnami/wordpress --allow-root option get default_comment_status
If this returns open, new posts will still accept comments regardless of what you see in the admin UI.
Set Default to Closed
sudo wp --path=/opt/bitnami/wordpress --allow-root option update default_comment_status closed
Close Comments on All Existing Posts
This is the step most people miss. You need to close comments on every published post individually.
sudo wp --path=/opt/bitnami/wordpress --allow-root post list --post_type=post --comment_status=open --fields=ID --format=ids | xargs -r sudo wp --path=/opt/bitnami/wordpress --allow-root post update --comment_status=closed
Do the same for pages.
sudo wp --path=/opt/bitnami/wordpress --allow-root post list --post_type=page --comment_status=open --fields=ID --format=ids | xargs -r sudo wp --path=/opt/bitnami/wordpress --allow-root post update --comment_status=closed
This doesn’t delete any existing comments — it just prevents new ones from being submitted. Your approved comments stay exactly where they are.
Disable Pingbacks
Pingbacks are another spam entry point. They were useful years ago for backlink notifications, but in practice they’re mostly abused by bots now. You can track who links to you through Google Search Console instead.
sudo wp --path=/opt/bitnami/wordpress --allow-root option update default_ping_status closed
Delete Spam Comments
First, list what’s in the spam folder to make sure you’re not deleting anything legit.
sudo wp --path=/opt/bitnami/wordpress --allow-root comment list --status=spam --fields=comment_ID,comment_author,comment_author_email,comment_date --format=table
Once you’ve confirmed they’re all spam, delete them.
sudo wp --path=/opt/bitnami/wordpress --allow-root comment list --status=spam --fields=comment_ID --format=ids | xargs -r sudo wp --path=/opt/bitnami/wordpress --allow-root comment delete --force
Find 404 Errors from Server Logs
If you’ve restructured your site or renamed posts, you’ll have old URLs returning 404 that Google still has indexed. These hurt your SEO and waste crawl budget. You can find them directly from your Apache access logs.
Check Recent 404s
sudo grep ' 404 ' /opt/bitnami/apache/logs/access_log | awk '{print $7}' | sort | uniq -c | sort -rn | head -30
This shows the most-hit 404 URLs in your current log file, sorted by hit count.
Include Rotated Logs
For a more complete picture, also check compressed log archives.
sudo zgrep ' 404 ' /opt/bitnami/apache/logs/access_log*.gz | awk -F'"' '{print $2}' | awk '{print $2}' | sort | uniq -c | sort -rn | head -50
Filter Out Bot Noise
Most 404s will be bots probing for vulnerabilities — things like /.env, /.git/config, /wp-content/plugins/hellopress/wp_filemanager.php, and random PHP files. You can ignore those. Focus on real content URLs.
sudo grep ' 404 ' /opt/bitnami/apache/logs/access_log | awk '{print $7}' | grep -E '^/(blog|topics|tutorials)' | sort | uniq -c | sort -rn
This filters to only show URLs that start with your content paths — the ones that actually matter for SEO.
Set Up 301 Redirects
Once you have the list of broken URLs, you need to map them to their new locations. A 301 redirect tells search engines the page has permanently moved, so they transfer the link equity to the new URL.
Get Your Current Post URLs
Export all published post slugs so you can match old URLs to current ones.
sudo wp --path=/opt/bitnami/wordpress --allow-root post list --post_type=post --post_status=publish --fields=ID,post_name,post_title --format=csv
Create a Redirect CSV for Import
The Redirection plugin supports CSV imports. Create a file with this format.
source,target,regex,type,code,match,hits,title
/tutorials/aws/how-to-add-new-users-on-ec2-ubuntu-18-04-server/,/blog/how-to-add-and-delete-users-on-ubuntu-ec2-wsl-or-any-server/,0,url,301,url,0,Old user management post
/tutorials/aws/ssh-without-password-on-linux-amazon-ec2-ubuntu/,/blog/how-to-setup-passwordless-ssh-login-on-ec2-ubuntu-22-04/,0,url,301,url,0,Old SSH post
/devops-tools/python-setup,/blog/how-to-install-and-manage-python-versions-on-wsl-ubuntu/,0,url,301,url,0,Old Python setup page
Each row maps an old URL to its new destination. For deleted posts that don’t have a direct replacement, redirect to your blog index (/blog/) instead of leaving them as 404s.
Import into the Redirection Plugin
- Go to Tools > Redirection in the WordPress admin
- Click the Import/Export tab
- Upload your CSV file
- Review and confirm the imported rules
After importing, test a few old URLs to make sure they redirect correctly.
Common Patterns to Watch For
When I ran this on my site, these were the most common types of 404s.
| Pattern | Cause | Fix |
|---|---|---|
/tutorials/aws/old-post-slug/ |
URL structure changed from /tutorials/ to /blog/ |
301 redirect to new /blog/ URL |
/devops-tools/python-setup |
Old section pages that were removed | 301 redirect to closest matching post |
/topics/old-tag-slug/ |
Deleted or renamed tag archive pages | 301 redirect to blog index |
/.env, /.git/config |
Bots scanning for exposed files | Ignore — not real traffic |
/blog/post-slug (no trailing slash) |
Missing trailing slash variant | Add redirect with and without slash |
Verify the Cleanup
After making all the changes, run a quick check to confirm everything is in order.
# Check no posts have open comments
sudo wp --path=/opt/bitnami/wordpress --allow-root post list --post_type=post --comment_status=open --format=count
# Check default comment status
sudo wp --path=/opt/bitnami/wordpress --allow-root option get default_comment_status
# Check unused tags (should be 0)
sudo wp --path=/opt/bitnami/wordpress --allow-root term list post_tag --fields=term_id --format=csv | awk -F"," 'NR>1 && $2==0' | wc -l
The first command should return 0. The second should return closed. The third should also return 0.
Conclusion
Running a cleanup like this once every few months keeps your WordPress site in good shape. Unused tags add noise to your sitemap, open comments invite spam, and 404s waste your Google crawl budget. WP-CLI makes it fast to fix all of these without clicking through the admin UI.
If your site runs on Apache and you want to keep an eye on errors, you might also want to set up Datadog monitoring for Apache. And if you’re managing your WordPress server on AWS, check out How to Install WordPress on EC2 Ubuntu 22.04 for the full setup guide.