(closest thing to native video lazy).
* - Auto-fills missing width / height attributes (best CLS win).
* - Excludes by substring patterns (src or class match) — useful for
* hero banner classes, logo files, etc.
*
* Tier: Free per FEATURES.md "Images" §1-6 (LiteSpeed parity — all
* Free in LS Cache).
*
* @package XSpeed
*/
declare(strict_types=1);
namespace XSpeed\Modules\Lazy;
defined( 'ABSPATH' ) || exit;
use XSpeed\Lazy_Loader;
use XSpeed\Module;
final class LazyModule extends Module {
public const SLUG = 'lazy';
public const TIER = self::TIER_FREE;
public const VERSION = '1.0.0';
public function ui_metadata(): array {
return array(
'label' => __( 'Media Optimization', 'xspeed' ),
'tab_label' => __( 'Lazy Loading', 'xspeed' ), // its own tab on the Media Optimization page
'icon' => 'Image',
'description' => __( 'Control how images, iframes, and videos load — lazy-loading, missing dimensions, and format optimization.', 'xspeed' ),
// Host page: Lazy Loading (this module) + Image Optimization (Pro)
// + AI Suggestions (Pro) as tabs — everything a page loads on one
// page instead of separate rows (FBS-83633). Fonts is NOT here: it
// has its own Optimization card (#86).
'custom_panel' => 'MediaPanel',
);
}
public function settings_schema(): array {
return array(
'lazy_images' => array(
'type' => 'bool',
'default' => true,
'label' => __( 'Lazy-load Images', 'xspeed' ),
'description' => __( 'Add loading="lazy" + decoding="async" to
tags in post content. The first images on the page get loading="eager" so the LCP image is not deferred.', 'xspeed' ),
),
'lazy_iframes' => array(
'type' => 'bool',
'default' => true,
'label' => __( 'Lazy-load Iframes', 'xspeed' ),
'description' => __( 'Add loading="lazy" to