Largest Contentful Paint (LCP) is the Core Web Vitals metric most directly improved by telling the browser how to prioritise resource loading. Two complementary tools — the fetchpriority="high" attribute and <link rel="preload"> — let you move the LCP image or hero section to the front of the browser’s fetch queue without JavaScript. WordPress 6.3+ applies fetchpriority="high" automatically to the first wp_get_attachment_image() in the main loop, but custom themes often need manual intervention.
Problem: A WordPress page has a large hero image that is the Largest Contentful Paint element — the image loads late because the browser discovers it only after parsing HTML and CSS, causing a high LCP score even with optimised images.
Solution: Add a <link rel="preload" as="image" fetchpriority="high"> tag for the LCP image in wp_head. Set fetchpriority="high" directly on the <img> element. Use loading="eager" on the LCP image and loading="lazy" on all below-fold images. Serve WebP or AVIF formats with a <picture> source fallback.
The code below adds fetchpriority="high" to a custom hero image, injects a preload hint for the LCP image via wp_head, and removes the WordPress auto-generated low-priority hint that conflicts with it.
<?php
// 1. Mark the hero attachment image as high priority
add_filter( 'wp_get_attachment_image_attributes',
function ( array $attr, WP_Post $attachment, $size ) {
// Only the designated hero image ID gets the high priority flag
if ( (int) $attachment->ID === (int) get_theme_mod( 'hero_image_id' ) ) {
$attr['fetchpriority'] = 'high';
$attr['loading'] = 'eager'; // override lazy-load default
unset( $attr['decoding'] ); // remove async decoding for hero
}
return $attr;
}, 10, 3
);
// 2. Inject a <link rel="preload"> for the hero image in <head>
add_action( 'wp_head', function () {
if ( ! is_front_page() ) {
return;
}
$image_id = (int) get_theme_mod( 'hero_image_id' );
if ( ! $image_id ) {
return;
}
$src = wp_get_attachment_image_url( $image_id, 'hero-1280' );
if ( ! $src ) {
return;
}
// Output preload — browser will fetch this before parser reaches <body>
printf(
'<link rel="preload" as="image" href="%s" fetchpriority="high">' . "\n",
esc_url( $src )
);
}, 1 ); // priority 1 = very early in <head>
// 3. Remove the low-priority preload WordPress auto-generates for backgrounds
add_filter( 'wp_preload_resources', function ( array $resources ) {
return array_filter( $resources, fn( $r ) =>
! isset( $r['as'] ) || $r['as'] !== 'image'
);
} );
NOTE: Using both fetchpriority="high" on the <img> tag and a <link rel="preload"> for the same image is intentionally redundant — the preload wins if the image is in CSS or a late-rendered component; the attribute wins when the <img> tag is in the initial HTML payload.