WordPress Image Optimization — Sizes, WebP, Lazy Loading and Alt Text Guide
In this tutorial, you'll learn to optimize images in WordPress — understanding how WordPress creates image sizes, converting to WebP format, enabling lazy loading, writing effective alt text, and using compression plugins for faster page loads.
What You'll Learn
- How WordPress creates multiple image sizes on upload (thumbnail, medium, medium_large, large)
- How to use the add_image_size() function in PHP for custom sizes
- What WebP format is and how to enable it in WordPress
- How lazy loading works (built-in since WP 5.5 with the loading="lazy" attribute)
- Why alt text matters for accessibility and SEO
- Which image compression plugins to use (Smush, ShortPixel, Imagify, EWWW)
- How to maintain aspect ratios when resizing
- How WordPress generates responsive images with srcset
- How to use CDNs for image delivery
Why It Matters
Images are the heaviest component of most web pages — often accounting for 60-80% of total page weight. A single unoptimized photo from a modern smartphone can be 5-10 MB, which takes 10+ seconds to load on a 4G connection. WordPress sites with optimized images load 3-5x faster, rank higher in Google, use less bandwidth, and provide a better experience for visitors on slow connections.
Real-World Use
An e-commerce site with 500 product pages has 3,000 product images totaling 2 GB. After optimizing: images converted to WebP (saving 40% size), lazy loading enabled (images load only when visible), custom thumbnail sizes created (no wasted pixels), and a CDN added — the total page weight drops from 8 MB to 1.2 MB, load time drops from 6 seconds to 1.5 seconds, and conversion rate increases by 15%.
Learning Path
flowchart LR
A[Media Library] --> B[Image Optimization]
B --> C[Comments & Discussion]
B --> D[Performance Basics]
How WordPress Creates Image Sizes
When you upload an image to WordPress, it automatically creates several copies at different dimensions. These are the default image sizes:
| Size Name | Default Dimensions | Cropped? | When to Use |
|---|---|---|---|
| Thumbnail | 150x150 | Yes (cropped to exact square) | Gallery grids, profile images, widget thumbnails |
| Medium | 300x300 | No (proportional) | Inline blog images, card thumbnails |
| Medium Large | 768x768 | No | Content area images on wider screens |
| Large | 1024x1024 | No | Full-width content images, featured images |
| Full | Original upload size | No | Photo galleries, downloadable originals |
# See all registered image sizes
wp media image-size
# Output: thumbnail (150x150, cropped)
# medium (300x300)
# medium_large (768x768)
# large (1024x1024)
# 1536x1536 (1536x1536)
# 2048x2048 (2048x2048)
Why Multiple Sizes?
Think of it as having different outfits for different occasions. The 150px thumbnail is for the blog sidebar. The 300px medium is for inline content. The 1024px large is for the featured hero image. Using the correct size means a sidebar thumbnail doesn't download a 4000px photo — saving bandwidth and load time.
// Display the correct size in your theme
the_post_thumbnail('thumbnail'); // 150x150
the_post_thumbnail('medium'); // 300x300
the_post_thumbnail('large'); // 1024x1024
the_post_thumbnail('full'); // Original size
The add_image_size() Function
You can register custom image sizes in your theme's functions.php:
// Add custom image sizes in functions.php
add_action('after_setup_theme', 'register_custom_image_sizes');
function register_custom_image_sizes() {
// Blog card thumbnail — 400x300, not cropped
add_image_size('blog-card', 400, 300, false);
// Featured hero — 1200x630, cropped to exact aspect ratio (like social share images)
add_image_size('featured-hero', 1200, 630, true);
// Gallery grid — 600x600, hard cropped to square
add_image_size('gallery-grid', 600, 600, array('center', 'center'));
}
The third parameter controls cropping:
false— proportional scaling (image fits within dimensions, no cropping)true— hard crop to exact dimensionsarray('center', 'center')— crop with focal point control
Regenerating Existing Images
New sizes only apply to future uploads. To create custom sizes for existing images:
# Install the Regenerate Thumbnails plugin, then:
wp media regenerate
# Or specify attachment IDs:
wp media regenerate 123 456 789
Removing Unused Default Sizes
If your theme doesn't use medium_large (768px), disable it to save disk space:
// Remove unused image sizes in functions.php
add_filter('intermediate_image_sizes', 'remove_unused_image_sizes');
function remove_unused_image_sizes($sizes) {
return array_diff($sizes, array('medium_large', '1536x1536', '2048x2048'));
}
WebP Format
WebP is a modern image format developed by Google that provides superior compression:
| Format | Quality | File Size |
|---|---|---|
| JPEG | 80% | 100 KB |
| WebP | Lossy (similar quality) | ~60 KB |
| PNG | Lossless | 200 KB |
| WebP Lossless | Lossless | ~80 KB |
WebP typically reduces file size by 25-35% compared to JPEG and by 50-75% compared to PNG.
How to Enable WebP in WordPress
Method 1: Server-Level Support (Fastest)
If your server supports WebP (most modern hosts do), WordPress automatically serves WebP when available:
// Check if the server supports WebP
if (image_webp_supported()) {
echo 'WebP is supported!';
}
Method 2: Using a Plugin
| Plugin | How It Works |
|---|---|
| WebP Express | Converts images on upload, serves WebP via server rules |
| ShortPixel | Converts to WebP during compression, serves via CDN |
| EWWW Image Optimizer | Converts to WebP, works with any server |
| Imagify | Converts to WebP with compression, bulk optimization |
// If using EWWW, enable WebP delivery via .htaccess rules
// EWWW handles this automatically in its settings
Method 3: Manual Conversion
Use an online converter or command-line tool, then upload the WebP version:
# Convert JPEG to WebP using cwebp (Google's converter)
cwebp -q 80 input.jpg -o output.webp
# Batch convert all JPEGs in a directory
for file in *.jpg; do
cwebp -q 80 "$file" -o "${file%.jpg}.webp"
done
Browser Compatibility
WebP is supported in all modern browsers (Chrome, Firefox, Edge, Safari 14+). For older browsers, use the <picture> element with a fallback:
<picture>
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description">
</picture>
WordPress handles this automatically when you upload WebP images with a JPEG fallback.
Lazy Loading
Lazy loading means images load only when they're about to appear on screen — not when the page first loads.
Built-In Lazy Loading (WordPress 5.5+)
Since WordPress 5.5, all images automatically get the loading="lazy" attribute:
<!-- WordPress adds this automatically -->
<img src="photo.jpg" alt="Description" loading="lazy" width="800" height="600">
How Lazy Loading Works
Page loads → Only above-the-fold images load
User scrolls → Browser checks which images are near the viewport
Near images → Browser downloads them just before they become visible
Far images → Still not loaded (saves bandwidth)
Excluding Images from Lazy Loading
Some images (hero banners, above-the-fold content) should load immediately:
// Disable lazy loading for specific images
add_filter('wp_img_tag_add_loading_attr', 'custom_loading_attr', 10, 2);
function custom_loading_attr($value, $image) {
// Disable for the first post thumbnail
if (strpos($image, 'wp-post-image') !== false && is_single()) {
return false;
}
return $value;
}
Performance Impact
| Scenario | Without Lazy Loading | With Lazy Loading |
|---|---|---|
| Page with 20 images | 20 images load immediately | Only 2-3 load (visible ones) |
| Initial page weight | 8 MB | 1.2 MB |
| Page load time | 6 seconds | 2 seconds |
| Data usage (scrolling full page) | 8 MB | 8 MB (same total, but felt faster) |
Alt Text Importance
Alt text (alternative text) is the text equivalent of an image. It serves three purposes:
Accessibility
Screen readers read alt text aloud for visually impaired users:
<img src="chart.jpg" alt="Bar chart showing 40% increase in sales from Q1 to Q2">
Without alt text: "Image" — the user has no idea what the image shows. With good alt text: "Bar chart showing 40% increase in sales from Q1 to Q2" — the user gets the full context.
SEO
Google uses alt text to understand image content. Images with descriptive alt text rank higher in Google Image Search.
<!-- Good for SEO -->
<img src="wp-logo.png" alt="WordPress logo displayed on a blue background">
<!-- Bad for SEO -->
<img src="wp-logo.png" alt="">
<img src="wp-logo.png" alt="image">
Broken Image Fallback
When an image fails to load, the browser displays the alt text instead:
[WordPress logo displayed on a blue background]
How to Write Good Alt Text
| Scenario | Good Alt Text | Bad Alt Text |
|---|---|---|
| Product photo | "Blue ceramic coffee mug on a wooden table with morning light" | "mug" |
| Screenshot | "WordPress settings page showing permalink options with the 'Post name' option selected" | "screenshot" |
| Logo | "Acme Corp logo" | "logo.png" |
| Decorative image | "" (empty alt — tells screen readers to skip it) | "decorative-border" |
// Ensure alt text is always populated
add_filter('wp_get_attachment_image_attributes', 'ensure_alt_text', 10, 3);
function ensure_alt_text($attr, $attachment, $size) {
if (empty($attr['alt'])) {
$attr['alt'] = get_the_title($attachment->ID);
}
return $attr;
}
Image Compression Plugins
Automatic compression saves you from manually optimizing every image:
| Plugin | Compression Type | Free Plan | WebP | CDN |
|---|---|---|---|---|
| Smush | Lossless | Yes (1 MB limit) | No (pro) | No |
| ShortPixel | Lossy + Lossless | Yes (100 images/month) | Yes | Yes (paid) |
| Imagify | Lossy + Lossless | Yes (25 MB/month) | Yes | No |
| EWWW Image Optimizer | Lossy + Lossless | Yes (unlimited) | Yes | No |
| WP Compress | Adaptive | Yes (limited) | Yes | Yes |
// EWWW configuration example (place in wp-config.php)
define('EWWW_IMAGE_OPTIMIZER_WEBP', true); // Enable WebP conversion
define('EWWW_IMAGE_OPTIMIZER_LAZY', false); // Disable built-in lazy load (use WP's)
define('EWWW_IMAGE_OPTIMIZER_CDN', 'https://cdn.yoursite.com');
What Compression Settings to Use
| Use Case | Setting | File Size Reduction |
|---|---|---|
| Photos on blog | Lossy 80% quality | 60-80% |
| Product images | Lossy 85% quality | 50-70% |
| Screenshots/text | Lossless | 10-30% |
| Background images | Lossy 70% quality | 70-85% |
Maintaining Aspect Ratios
When images are resized but not cropped (proportional), they maintain their original aspect ratio:
// Add_image_size with hard crop maintains exact dimensions
add_image_size('blog-card', 400, 300, true);
// Without crop, the image scales proportionally
// A 600x400 image becomes 400x267 (not 400x300)
CSS for Aspect Ratio Containers
/* Maintain aspect ratio with CSS */
.card-image {
aspect-ratio: 4 / 3;
object-fit: cover;
}
Common Aspect Ratios
| Ratio | Common Use | Example Dimensions |
|---|---|---|
| 1:1 | Profile photos, thumbnails | 150x150 |
| 4:3 | Standard photos | 800x600 |
| 16:9 | Hero banners, videos | 1920x1080 |
| 3:2 | Landscape photography | 1200x800 |
| 2:3 | Portrait photography | 800x1200 |
Responsive Images with srcset
WordPress automatically generates srcset and sizes attributes for images inserted into posts:
<img src="photo-1024x768.jpg"
srcset="photo-300x225.jpg 300w,
photo-768x576.jpg 768w,
photo-1024x768.jpg 1024w,
photo-1920x1440.jpg 1920w"
sizes="(max-width: 1024px) 100vw, 1024px"
alt="Description"
loading="lazy">
The browser uses srcset and sizes to choose the best image size for the user's screen:
- A phone user (375px screen) gets the 300px version
- A tablet user (768px screen) gets the 768px version
- A desktop user (1920px screen) gets the 1024px or full-size version
// Customize the srcset sizes attribute
add_filter('wp_calculate_image_sizes', 'custom_sizes', 10, 2);
function custom_sizes($sizes, $size) {
return '(max-width: 768px) 100vw, 768px';
}
CDN for Images
A Content Delivery Network (CDN) stores copies of your images on servers around the world and serves them from the closest location to each visitor.
| CDN | Cost | Image Optimization Included |
|---|---|---|
| Cloudflare | Free plan available | Polish (automatic image optimization) |
| BunnyCDN | $1/month + bandwidth | Optimization add-on |
| ShortPixel CDN | Paid | Yes (WebP, compression) |
| Imgix | Paid | Real-time image processing |
| Cloudinary | Free tier | Automatic optimization and transformations |
// Configure CDN upload URL in wp-config.php
define('WP_CONTENT_URL', 'https://cdn.yoursite.com/wp-content');
// Requires DNS setup and CDN configuration
Cloudflare Polish Setup
With Cloudflare's free plan, enable "Polish" to automatically:
- Strip EXIF data (metadata)
- Compress images
- Convert to WebP (when supported by browser)
Common Mistakes
Uploading images at original camera resolution: A 4000x3000 photo (12 MP) is massive overkill for a blog that displays images at 800px wide. Resize to 1920px max before uploading.
Relying only on WordPress for compression: WordPress does not compress images. Always use a compression plugin or compress before upload. An uncompressed 1 MB JPEG can be 200 KB with no visible quality loss.
Not setting explicit width and height: Without width and height attributes, the browser cannot reserve space for images, causing layout shifts (Cumulative Layout Shift — a Core Web Vitals metric).
Using full-size images in galleries: When you insert a gallery, choose "Thumbnail" or "Medium" size — not "Full." Full-size galleries load megabytes of data for small grid previews.
Forgetting alt text on decorative images: Decorative images (borders, spacers, icons) should have
alt=""(empty) so screen readers skip them. Missing this creates an annoying "image, image, image" experience for screen reader users.
Practice Questions
- What are the five default image sizes WordPress creates, and what are their dimensions?
- What is lazy loading, and how does it improve page performance?
- What should you include in alt text for a product image on an e-commerce site?
Challenge: Audit a single blog post's images. Check each image's file size, dimensions, format, alt text, and whether lazy loading is enabled. Create a report showing: current total image weight, estimated weight after WebP conversion, estimated weight after resizing, and the alt text improvements needed. Then implement all optimizations and measure the before/after page load time.
FAQ
Mini Project
Fully optimize a post with images:
- Upload 5 images (resized to max 1920px, compressed with a tool or plugin)
- Verify WordPress created all default sizes and note the file sizes
- Register a custom size
blog-card(400x300, cropped) in functions.php - Regenerate thumbnails for all existing images
- Convert all 5 images to WebP format
- Write descriptive alt text for each image
- Insert images into a post with correct sizes and alignment
- Verify lazy loading is active (check HTML for
loading="lazy") - Test the page with Chrome DevTools > Network tab — verify images load only when scrolled to
- Measure the total page weight before and after optimization
What's Next
Now that images are optimized, learn Comments and Discussion to build community engagement around your content. Then explore performance optimization more broadly.
For more on media, see Media Library and Page Templates.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro