wordpress-实现自定义响应式图片加载

WordPress 原生函数 wp_get_attachment_image_srcset,可以实现响应式图片加载,但这只是针对媒体库图片,在网站开发,有时图片素菜放置主题目录下,这时原生函数就无法调用了,为了完全控制图片质量和版本,为此开发自定义响应式图片加载。

◆ 图片宽度数值设计

断点范围宽度适用场景DPR处理
≤480px600w手机竖屏2x自动适配
481-768px900w手机横屏/小平板浏览器自动优化
769-1024px1200w平板/小笔记本浏览器自动优化
1025-1440px1600w主流桌面显示器浏览器自动优化
≥1441px2000w4K/大屏设备浏览器自动优化
比例适用场景尺寸(宽×高)
16:9视频封面、横幅图1920×1080
4:3博客文章配图1200×900
1:1头像、图标600×600
3:2摄影作品1200×800

♦  代码实现

参考上面表格,结合实际业务场景,我打算用4张不同尺寸图片。分别是640px、960px、1280px、1920px。刚好和DPR倍数适配,如640适配2倍DPR,则是1280px。3倍则是1920px。

◆ class-responsive-image-handler.php

<?php
namespace CHENZZ_THEME\Inc;
use CHENZZ_THEME\Inc\Traits\Singleton;
/**
 * Responsive_Image_Handler 类负责处理非媒体库图片的响应式显示
 * 它使用单例模式确保整个应用中只有一个该类的实例
 */
class Responsive_Image_Handler {
    use Singleton;
    protected function __construct() {
        // load class.
    }
    /**
     * 生成图片的完整 URL
     *
     * @param string $src 图片文件名(不包含扩展名)
     * @param string $format 图片格式,如 'webp' 或 'jpg'
     * @return string 生成的图片完整 URL
     */
    public function generate_source($src, $format) {
        $file = "{$src}.{$format}";
        return esc_url(get_template_directory_uri().'/assets/src/img/'.$file);
    }
    /**
     * 获取响应式图片的 src 或 srcset 信息
     *
     * @param string $filename 图片文件名(不包含尺寸和扩展名)
     * @param string $size 图片尺寸,默认为 'full',表示生成完整的 srcset
     * @param string $defaultFormat 图片默认格式,默认为 'jpg'
     * @return string 单尺寸请求时返回图片的 src URL,完整请求时返回 srcset 字符串
     */
    public function get_theme_responsive_image($filename, $size = 'full', $defaultFormat = 'jpg') {
        // 基础配置,定义图片存储的基础目录
        $base_dir = '/assets/src/img/';
        $sizes_config = [
            'sm' => ['width' => 640,  'dpr' => [1,2], 'format' => ['webp', 'jpg']],
            'md' => ['width' => 960,  'dpr' => [1,2], 'format' => ['webp', 'jpg']],
            'lg' => ['width' => 1280, 'dpr' => [1], 'format' => ['webp', 'jpg']],
            'xl' => ['width' => 1920, 'dpr' => [1],   'format' => ['webp', 'jpg']]
        ];
        // 安全检测,如果请求的尺寸不在配置中且不是 'full',则返回 fallback 图片的 URL
        if (!array_key_exists($size, $sizes_config) && $size !== 'full') {
            return esc_url(get_template_directory_uri().$base_dir.'fallback.jpg');
        }
        // 单尺寸请求处理,如果请求的不是完整的 srcset
        if ($size !== 'full') {
            // 获取请求尺寸的配置信息
            $target = $sizes_config[$size];
            // 拼接图片文件名(包含尺寸)
            $src = "{$filename}-{$target['width']}w";
            // 调用 generate_source 方法生成该图片的 URL 并返回
            return $this->generate_source($src, $defaultFormat);
        }
        // 生成完整 srcset
        $sources = [];
        // 遍历所有尺寸配置
        foreach ($sizes_config as $breakpoint) {
            // 遍历每个尺寸对应的设备像素比(DPR)
            foreach ($breakpoint['dpr'] as $dpr) {
                $width = $breakpoint['width'] * $dpr;
                $src = "{$filename}-{$width}w";
                // 只添加指定格式的图片链接
                if (in_array($defaultFormat, $breakpoint['format'])) {
                    // 调用 generate_source 方法生成图片 URL,并添加宽度描述符,然后存入数组
                    $sources[] = $this->generate_source($src, $defaultFormat) . " {$width}w";
                }
            }
        }
        // 将数组中的元素用逗号连接成字符串,并去除重复项,最后返回该字符串作为 srcset
        return implode(', ', array_unique($sources));
    }
}

html实现

<? php 
$responsive_image_handler_class = \CHENZZ_THEME\Inc\Responsive_Image_Handler::get_instance();  
?>
    <picture>
        <source type="image/webp" srcset="<?php echo $responsive_image_handler_class->get_theme_responsive_image('about-fanhua5', 'full', 'webp'); ?>">
        <img class="responsive-bg-image"
             src="<?php echo $responsive_image_handler_class->get_theme_responsive_image('about-fanhua5', 'lg', 'jpg'); ?>"
             srcset="<?php echo $responsive_image_handler_class->get_theme_responsive_image('about-fanhua5', 'full', 'jpg'); ?>"
             sizes="(max-width: 640px) 640px,
                (max-width: 960px) 960px,
                (max-width: 1280px) 1280px,
                1920px"
             alt="<?php esc_attr_e('《繁花》人物关系全景图', 'textdomain'); ?>"
             loading="lazy"
             decoding="async">
    </picture>

浏览器显示结果

<picture>
    <source type="image/webp" srcset="https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-640w.webp 640w,
 https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-1280w.webp 1280w,
 https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-960w.webp 960w,
 https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-1920w.webp 1920w">
    <img class="responsive-bg-image"
         src="https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-1280w.jpg"
         srcset="https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-640w.jpg 640w,
 https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-1280w.jpg 1280w,
 https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-960w.jpg 960w,
 https://example3.chenzhuzhen.cn/wp-content/themes/example3/assets/src/img/about-fanhua5-1920w.jpg 1920w"
         sizes="(max-width: 640px) 640px,
(max-width: 960px) 960px,
(max-width: 1280px) 1280px,
1920px"
         alt="《繁花》人物关系全景图"
         loading="lazy"
         decoding="async">
</picture>

♦  媒体库相关函数

◆ wp_get_attachment_metadata

$image_meta = wp_get_attachment_metadata( $attachment_id );

Array
(
    [width] => 2000
    [height] => 1411
    [file] => 2025/02/fanhua-10-5.jpg
    [filesize] => 427780
    [sizes] => Array
        (
        )

    [image_meta] => Array
        (
            [aperture] => 0
            [credit] => 
            [camera] => 
             => 
            [created_timestamp] => 0
            [copyright] => 
            [focal_length] => 0
            [iso] => 0
            [shutter_speed] => 0
            [title] => 
            [orientation] => 1
            [keywords] => Array
                (
                )

        )

)

查看php当前内容限制

echo '<pre>';
print_r('当前 WordPress 内存限制: '. ini_get('memory_limit'));
wp_die();
// 当前 WordPress 内存限制: 128M