This applies the loading="lazy" attribute to all images inside widget areas using a safe regex with no DOM parsing overhead.
/**
* Add loading="lazy" to all images rendered inside WordPress widget areas.
* Skips images that already have a loading attribute or are marked eager.
*
* No JavaScript, no plugin, no DOM parser — pure regex on widget HTML output.
*/
// ─── Apply to text widgets (classic widget text) ──────────────────────────────
add_filter( 'widget_text', 'wpfolks_lazy_load_widget_images', 20 );
// ─── Apply to all widget output via output buffering ─────────────────────────
add_filter( 'dynamic_sidebar_params', 'wpfolks_buffer_widget_output' );
function wpfolks_buffer_widget_output( array $params ): array {
ob_start( 'wpfolks_lazy_load_widget_images' );
return $params;
}
// ─── Core transformer — reusable by both hooks ───────────────────────────────
function wpfolks_lazy_load_widget_images( string $content ): string {
if ( empty( $content ) ) return $content;
// Match <img> tags that don't already have a loading attribute
return preg_replace_callback(
'/<imgb([^>]*?)>/i',
function ( array $matches ): string {
$tag = $matches[0];
$attrs = $matches[1];
// Skip if loading attribute already present
if ( preg_match( '/bloadings*=/i', $attrs ) ) {
return $tag;
}
// Skip WordPress-generated no-lazy markers
if ( strpos( $attrs, 'data-no-lazy' ) !== false ) {
return $tag;
}
// Insert loading="lazy" before the closing >
return '<img' . $attrs . ' loading="lazy">';
},
$content
) ?? $content;
}