Native lazy loading arrived in core and is filterable

5.5 adds loading="lazy" to images in content automatically, which is a good default and is wrong for the first image on the page.

// the whole thing off
add_filter( 'wp_lazy_loading_enabled', '__return_false' );

// or per context, which is the useful form
add_filter( 'wp_lazy_loading_enabled', function ( $default, $tag, $context ) {
    if ( 'the_content' === $context && ! turkerdev_is_first_image() ) {
        return $default;
    }

    return 'wp_get_attachment_image' === $context ? $default : false;
}, 10, 3 );

Lazy-loading the hero image delays the Largest Contentful Paint rather than improving it, and core applies the attribute to everything in the content without knowing which is which. 5.5 also requires width and height on the image for the attribute to be added, which is a deliberate and correct constraint — without dimensions the lazy load causes layout shift. Core refined this in later releases specifically because of the first-image problem.