How to Clean Up Your WordPress Site with WP-CLI

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

  1. Go to Tools > Redirection in the WordPress admin
  2. Click the Import/Export tab
  3. Upload your CSV file
  4. 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.