How to Optimize LCP Images in WordPress Themes
How to Optimize LCP Images in WordPress Themes
On most WordPress sites, the Largest Contentful Paint (LCP) element is an image—usually a hero image,
featured image, or a large above-the-fold thumbnail. If that image loads late, your LCP score suffers,
even if everything else is optimized.
This guide shows theme-level, code-based fixes to make LCP images load earlier and render faster:
- Ensure the correct image size is used (not too large, not too small)
- Stop lazy-loading the LCP image
- Add
fetchpriority="high"and optionally preload - Provide correct dimensions to prevent layout shifts
- Reduce work the browser does before downloading the image
Step 1: Identify Your LCP Image (Don’t Guess)
Common LCP image sources:
- Homepage hero image
- Single post featured image
- Category/archive thumbnails (first item)
A theme optimization should target these predictable locations. You typically only want 1 image per page
to get “priority” treatment.
Step 2: Use the Right Image Size (Avoid Full-Size by Accident)
The fastest LCP win is often preventing full-size images from being used above the fold.
If you output a full-resolution attachment where a 1200px image would do, you’ll inflate download time.
Use wp_get_attachment_image() with a Named Size
<?php
// Example: featured image in single.php or template part
if ( has_post_thumbnail() ) {
echo wp_get_attachment_image(
get_post_thumbnail_id(),
'large', // choose an appropriate size for your layout
false,
array(
'class' => 'hero-image',
'alt' => trim( strip_tags( get_the_title() ) ),
)
);
}
?>
Avoid hardcoding the attachment URL unless you have a strong reason.
Let WordPress generate srcset and sizes.
Define a Dedicated “LCP/Hero” Size (Theme Controlled)
If your theme has a consistent hero layout, define a dedicated size and use it everywhere.
<?php
add_action( 'after_setup_theme', function () {
// Example: 1280px wide hero with a common aspect ratio.
add_image_size( 'wpct-hero', 1280, 720, true );
} );
Then output it:
<?php
echo wp_get_attachment_image(
get_post_thumbnail_id(),
'wpct-hero',
false,
array(
'class' => 'hero-image',
'alt' => trim( strip_tags( get_the_title() ) ),
)
);
?>
Step 3: Do NOT Lazy-Load the LCP Image
Lazy-loading is great for below-the-fold images, but harmful for the LCP image.
If the hero image has loading="lazy", the browser delays it—your LCP goes up.
Manually Set loading=”eager” for the Hero Image
<?php
echo wp_get_attachment_image(
get_post_thumbnail_id(),
'wpct-hero',
false,
array(
'class' => 'hero-image',
'loading' => 'eager',
'decoding' => 'async',
)
);
?>
Use this only for the true LCP image (typically the first large image above the fold).
Theme-Level Filter: Remove Lazy-Loading for a Specific Class
If your theme always applies a class to the LCP image (recommended),
you can enforce eager loading via a filter.
<?php
add_filter( 'wp_get_attachment_image_attributes', function ( $attr, $attachment, $size ) {
if ( empty( $attr['class'] ) ) {
return $attr;
}
// Only target your hero/LCP class
if ( strpos( $attr['class'], 'hero-image' ) !== false ) {
$attr['loading'] = 'eager';
$attr['decoding'] = 'async';
}
return $attr;
}, 10, 3 );
Step 4: Add fetchpriority=”high” to the LCP Image
Modern browsers support fetchpriority.
Setting fetchpriority="high" tells the browser the image is important and should be fetched early.
Add fetchpriority via Attributes
<?php
echo wp_get_attachment_image(
get_post_thumbnail_id(),
'wpct-hero',
false,
array(
'class' => 'hero-image',
'loading' => 'eager',
'fetchpriority' => 'high',
)
);
?>
Enforce fetchpriority for the Hero Class (Filter)
<?php
add_filter( 'wp_get_attachment_image_attributes', function ( $attr, $attachment, $size ) {
if ( ! empty( $attr['class'] ) && strpos( $attr['class'], 'hero-image' ) !== false ) {
$attr['fetchpriority'] = 'high';
$attr['loading'] = 'eager';
$attr['decoding'] = 'async';
}
return $attr;
}, 20, 3 );
Only apply fetchpriority="high" to one image per page.
If everything is “high priority”, nothing is.
Step 5: Add a Preload for the LCP Image (Use Carefully)
Preload can improve LCP by starting the download earlier.
But preload must match the actual selected resource (responsive images can complicate this).
If your LCP image uses a single fixed URL (or you can reliably choose the correct candidate),
preload can help.
Preload the Exact Image URL for a Known Hero Attachment
<?php
add_action( 'wp_head', function () {
if ( ! is_singular( 'post' ) ) return;
if ( ! has_post_thumbnail() ) return;
$id = get_post_thumbnail_id();
$src = wp_get_attachment_image_url( $id, 'wpct-hero' );
if ( ! $src ) return;
echo '<link rel="preload" as="image" href="' . esc_url( $src ) . '" fetchpriority="high">' . "\n";
}, 1 );
Use preload only when you’re confident it matches what you output.
If the browser preloads one resource and then downloads another, you can waste bandwidth.
Step 6: Always Output Width/Height to Prevent CLS
Even if LCP is fast, you can still fail Core Web Vitals with CLS.
An image without dimensions causes layout shift when it loads.
wp_get_attachment_image() outputs width/height by default.
Avoid stripping them out. If your CSS makes images responsive, use:
<?php
// CSS concept (place in your stylesheet)
.hero-image {
max-width: 100%;
height: auto;
}
If your design needs a fixed aspect ratio container (common for heroes),
use a wrapper and object-fit:
<?php
// HTML structure concept
// <div class="hero-media"> ... image ... </div>
<?php
// CSS concept
.hero-media {
aspect-ratio: 16 / 9;
overflow: hidden;
}
.hero-media img {
width: 100%;
height: 100%;
object-fit: cover;
}
Step 7: Don’t Block the Image with Late CSS/JS
Your LCP image can be delayed by render-blocking assets:
- Heavy CSS that blocks painting
- JS that injects the hero later (sliders are common culprits)
- Hero images loaded via CSS
background-image(harder to prioritize)
For LCP, prefer an actual <img> element over CSS background images.
Browsers can prioritize <img> far more reliably.
If You Must Use a Background Image
A background image can still become LCP, but it’s harder to optimize.
If possible, switch to:
<img>withobject-fit: cover- Or
<picture>for art direction
Step 8: Optimize the File Itself
Theme code can’t fully compensate for an oversized image.
Make sure:
- Use modern formats when available (WebP/AVIF)
- Compress aggressively for the hero size
- Avoid unnecessary metadata
If you use a dedicated hero size, you can enforce consistent compression workflow per size.
Practical “Best Default” Recipe for Theme Developers
- Create a dedicated hero image size (
wpct-hero) - Output it with
wp_get_attachment_image()sosrcsetworks - Force
loading="eager"only for the hero - Add
fetchpriority="high"only for the hero - Optionally preload the exact URL if your selection is deterministic
- Keep width/height attributes to prevent CLS
Example: Full LCP-Optimized Featured Image Output (Single Post)
<?php
if ( is_singular( 'post' ) && has_post_thumbnail() ) {
echo '<div class="hero-media">';
echo wp_get_attachment_image(
get_post_thumbnail_id(),
'wpct-hero',
false,
array(
'class' => 'hero-image',
'alt' => trim( strip_tags( get_the_title() ) ),
'loading' => 'eager',
'decoding' => 'async',
'fetchpriority' => 'high',
)
);
echo '</div>';
}
?>
Common Mistakes
- Lazy-loading the hero image
- Using full-size images above the fold
- Preloading the wrong responsive candidate
- Removing width/height attributes (CLS)
- Putting the hero behind a JS slider/carousel
- Setting multiple images to
fetchpriority="high"
Summary
- LCP image optimization is mostly about prioritization and correct sizing
- Use
wp_get_attachment_image()with a dedicated hero size - Disable lazy loading for the hero and set
fetchpriority="high" - Preload only when you can confidently target the correct resource
- Keep dimensions to prevent CLS and avoid JS-heavy hero patterns
Treat the LCP image as a first-class performance asset. When your theme outputs it correctly,
Core Web Vitals improvements become consistent across the entire site.
🎨 Want to learn more? Visit our WordPress Customization Hub for tips and advanced techniques.