Menü schliessen
Created: December 29th 2025
Last updated: December 29th 2025
Categories: Databases,  IT Development,  Linux,  MySQL,  Php
Author: Natasa Josipovic

Clean Up WordPress Uploads Folder: Step-by-Step Script Solution for Image Optimization

WordPress media libraries can quickly become bloated with unnecessary image sizes, consuming valuable server storage and slowing down your site. Every time you upload an image, WordPress automatically generates multiple thumbnail versions—many of which your theme never actually uses. This creates a storage problem that impacts both hosting costs and site performance.

This comprehensive guide walks you through a complete WordPress image optimization workflow using custom bash scripts and proven techniques. You'll learn how to identify unused image sizes, implement WebP conversion, and maintain a lean media library—all while preserving image quality.

Note: These scripts are designed for Linux/Unix environments (including macOS). Windows users can run them using WSL (Windows Subsystem for Linux) or adapt them for PowerShell. Alternatively, you can SSH into your Linux-based hosting server to execute the scripts directly.

Understanding the Problem: WordPress Image Size Bloat

WordPress automatically generates multiple image sizes for every uploaded file. By default, WordPress creates three main sizes: Thumbnail, Medium, and Large. The exact dimensions of these sizes can be configured in Settings → Media, and each WordPress installation may have different values based on administrator preferences.

Beyond these default sizes, WordPress also generates additional intermediate sizes (like medium_large, and since version 5.3, sizes up to 1536×1536 and 2048×2048 for high-resolution displays). However, the real storage problem often comes from themes and plugins that register their own custom image sizes—many of which are never actually used on your site. When you factor in originals and all their various thumbnails, a single uploaded image can spawn 8-10 or even more files.

The Custom Image Size Problem

Many themes and plugins add their own custom image sizes through code. These are typically defined in the theme's functions.php file using the add_image_size() function. To check if your site has custom image sizes, search your active theme for:

# Navigate to your theme directory
cd ~/path/to/wp-content/themes/your-theme

# Search for custom image size definitions
grep -rn "add_image_size\|image_setup" --include="*.php"

You might find code similar to this:

function image_setup() {
    add_theme_support('post-thumbnails');
    add_image_size('custom-size-1', 768, 914, true);
    add_image_size('custom-size-2', 725, 914, true); 
}
add_action('after_setup_theme', 'image_setup');

The critical question: Are these custom sizes actually being used in your theme templates?

In many cases, custom sizes were added during initial development but are no longer referenced anywhere in the theme. Yet WordPress continues generating these sizes for every single uploaded image, wasting storage space. It's not uncommon to find 5-10 registered image sizes when only 2-3 are actually displayed on your website.

Step 1: Audit Your Current Image Sizes

Before making any changes, analyze which image sizes your theme actually uses.
Search your theme files for image-related functions:

# Navigate to your theme directory
cd ~/path/to/wp-content/themes/your-theme

# Search for image function calls
grep -rn "the_post_thumbnail\|get_the_post_thumbnail\|wp_get_attachment_image" --include="*.php"

This reveals which registered image sizes appear in your theme code. Common sizes include 'thumbnail', 'medium', 'large', 'full', and any custom sizes your theme defines.

Important: If you found custom sizes in your theme that are NOT used in any template files, you should remove those add_image_size() calls from your functions.php to prevent WordPress from generating them for future uploads.

Step 2:  Clean Up Existing Unnecessary Image Sizes

Create a bash script to identify and remove image sizes not registered in your WordPress configuration.

Important: Before running this script, you need to modify the KEEP_SIZES variable to match the image sizes your theme actually uses (which you identified in the audit step).

#!/bin/bash

# Script: cleanup-unused-image-sizes.sh
# Purpose: Remove WordPress image thumbnails that are not registered in your theme

echo "════════════════════════════════════════"
echo " WORDPRESS IMAGE CLEANUP SCRIPT"
echo "════════════════════════════════════════"

# Define which sizes to KEEP (update based on your configuration)
# Adjust these patterns to match YOUR WordPress settings
KEEP_SIZES="150x150|300x[0-9]+|768x[0-9]+|1024x[0-9]+|1920x[0-9]+"

# Count files to be removed
COUNT=$(find . -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" -o -name "*.webp" \) \
    -regextype posix-extended \
    -regex '.*-[0-9]+x[0-9]+\.(jpg|jpeg|png|webp)$' \
    ! -regex ".*-(${KEEP_SIZES})\.(jpg|jpeg|png|webp)$" \
    ! -name 'cropped-favicon-*' \
    | wc -l)

echo "📊 Files to remove: $COUNT"

# Calculate size to be freed
SIZE=$(find . -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" -o -name "*.webp" \) \
    -regextype posix-extended \
    -regex '.*-[0-9]+x[0-9]+\.(jpg|jpeg|png|webp)$' \
    ! -regex ".*-(${KEEP_SIZES})\.(jpg|jpeg|png|webp)$" \
    ! -name 'cropped-favicon-*' \
    -exec du -ch {} + 2>/dev/null | grep total$ | awk '{print $1}')

echo "💾 Space to be freed: $SIZE"
echo ""
echo "Sizes to KEEP (adjust KEEP_SIZES variable as needed):"
echo " ✅ Thumbnail (e.g., 150x150)"
echo " ✅ Medium (e.g., 300x*, 768x*)"
echo " ✅ Large (e.g., 1024x*, 1920x*)"
echo " ✅ Your custom sizes if still needed"
echo ""

read -p "Continue with deletion? (y/n): " -n 1 -r
echo

if [[ $REPLY =~ ^[Yy]$ ]]; then
    echo "🔄 Deleting files..."
    
    find . -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" -o -name "*.webp" \) \
        -regextype posix-extended \
        -regex '.*-[0-9]+x[0-9]+\.(jpg|jpeg|png|webp)$' \
        ! -regex ".*-(${KEEP_SIZES})\.(jpg|jpeg|png|webp)$" \
        ! -name 'cropped-favicon-*' \
        -delete
    
    echo "✅ Cleanup complete!"
else
    echo "❌ Operation cancelled"
fi

Run this script from your uploads directory:

cd ~/path/to/wp-content/uploads
chmod +x cleanup-unused-image-sizes.sh
./cleanup-unused-image-sizes.sh

Step 3:  Regenerate Required Thumbnails

After cleanup, regenerate any missing required sizes using the "Regenerate Thumbnails" plugin:

  • Install and activate "Regenerate Thumbnails" from WordPress plugin repository
  • Navigate to Tools → Regenerate Thumbnails
  • Enable "Skip regenerating existing correctly sized thumbnails"
  • Disable "Delete old unregistered sizes" (you already cleaned these)
  • Click "Regenerate All Thumbnails"

Step 4: Convert Images to WebP Format

WebP provides superior compression compared to JPG and PNG while maintaining visual quality. Here's a production-ready conversion script:

Install ImageMagick first:

sudo apt update sudo apt install imagemagick convert --version # Verify installation 
#!/bin/bash

# Script: convert-to-webp.sh
# Purpose: Convert JPG/PNG images to WebP format with quality preservation
# Dependencies: ImageMagick

echo "════════════════════════════════════════"
echo " WEBP CONVERSION SCRIPT"
echo "════════════════════════════════════════"

# Verify ImageMagick is installed
if ! command -v convert &> /dev/null; then
    echo "❌ ImageMagick not found. Install with: sudo apt install imagemagick"
    exit 1
fi

# Count files for conversion
TOTAL=$(find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | wc -l)
echo "📊 Images found: $TOTAL"

# Check existing WebP files
EXISTING_WEBP=$(find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | while read -r file; do
    base="${file%.*}"
    output="${base}.webp"
    if [ -f "$output" ]; then
        echo "1"
    fi
done | wc -l)

TO_CONVERT=$((TOTAL - EXISTING_WEBP))
echo "✅ Already converted: $EXISTING_WEBP"
echo "🔄 Remaining: $TO_CONVERT"
echo ""
echo "Settings:"
echo " 📸 JPG/JPEG: quality 85 (high quality)"
echo " 🖼  PNG: quality 100 (lossless)"
echo ""

read -p "Continue with conversion? (y/n): " -n 1 -r
echo

if [[ $REPLY =~ ^[Yy]$ ]]; then
    echo "🔄 Converting images..."
    echo "⏳ This may take 30-60 minutes for large libraries..."
    
    COUNT=0
    CONVERTED=0
    
    find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | while read -r file; do
        base="${file%.*}"
        ext="${file##*.}"
        output="${base}.webp"
        
        # Skip if WebP already exists
        if [ -f "$output" ]; then
            continue
        fi
        
        # Set quality based on format
        if [[ "${ext,,}" == "jpg" || "${ext,,}" == "jpeg" ]]; then
            quality=85
        else
            quality=100
        fi
        
        # Convert to WebP
        convert "$file" -quality "$quality" "$output" 2>/dev/null
        
        if [ $? -eq 0 ]; then
            CONVERTED=$((CONVERTED + 1))
        fi
        
        COUNT=$((COUNT + 1))
        
        # Progress indicator every 100 files
        if (( COUNT % 100 == 0 )); then
            PERCENT=$((COUNT * 100 / TOTAL))
            echo "📊 Progress: $COUNT/$TOTAL ($PERCENT%) - Converted: $CONVERTED"
        fi
    done
    
    echo "✅ Conversion complete!"
    WEBP_COUNT=$(find . -name "*.webp" -type f | wc -l)
    echo "📊 Total WebP files: $WEBP_COUNT"
else
    echo "❌ Conversion cancelled"
fi

Step 5: Update Database References

After WebP conversion, update your database to reference the new file format.

Option A: Using a Plugin (Recommended for Beginners)
Use the "Better Search Replace" plugin for a user-friendly interface:

  • Install and activate "Better Search Replace"
    Navigate to Tools → Better Search Replace
    First, run a dry run to see how many changes will be made:
  • Search for: .jpg
    Replace with: .webp
    Select tables: wp_posts, wp_postmeta, wp_options
    Enable "Run as dry run"
  • If the dry run looks correct, uncheck "Run as dry run" and execute
    Repeat for PNG files (.png → .webp)

Option B: Using WP-CLI (Command Line)
For those comfortable with command line, WP-CLI offers a faster approach:

# Navigate to WordPress root directory
cd ~/path/to/wordpress

# Replace .jpg with .webp
wp search-replace '.jpg' '.webp' wp_posts wp_postmeta wp_options --dry-run

# If dry run looks good, run without --dry-run flag
wp search-replace '.jpg' '.webp' wp_posts wp_postmeta wp_options

# Replace .png with .webp
wp search-replace '.png' '.webp' wp_posts wp_postmeta wp_options

Note: Always create a database backup before performing search-replace operations

Step 6: Remove Old JPG/PNG Files

After confirming WebP files work correctly and database is updated:

# Create backup first
cd ~/path/to/wp-content
tar -czf uploads-backup-$(date +%Y%m%d).tar.gz uploads/

# Remove old format files
cd uploads
find . -type f \( -name "*.jpg" -o -name "*.jpeg" -o -name "*.png" \) -delete

# Verify new size
du -sh .

Conclusion

Implementing these optimization techniques provides complete control over WordPress media storage while significantly reducing hosting costs and improving site performance. The custom bash scripts offer flexibility that commercial plugins can't match, allowing you to tailor the optimization to your specific needs.

By preventing unnecessary thumbnail generation, converting to modern image formats, and maintaining only required sizes, you create a sustainable media management workflow that scales efficiently as your site grows.