分析 `wp_get_attachment_image_src()` 函数的源码,它是如何获取媒体附件的图片的?

哈喽大家好,我是你们的老朋友,代码界的段子手。今天咱们来聊聊 WordPress 里一个非常实用又有点神秘的函数:wp_get_attachment_image_src()。 别看它名字长,功能其实很简单,就是帮你搞到媒体附件(比如你上传的图片)的 URL、宽度和高度。但要真正理解它,咱们得扒开它的源码,看看它到底是怎么运作的。

一、热身:wp_get_attachment_image_src() 是什么?

简单来说,wp_get_attachment_image_src() 函数接收两个主要的参数:

  • $attachment_id:附件的 ID,也就是你在 WordPress 后台上传图片后,系统分配给它的唯一标识符。
  • $size:你想要的图片尺寸。可以是预定义的尺寸(如 ‘thumbnail’、’medium’、’large’、’full’),也可以是自定义的尺寸,甚至是一个包含宽度和高度的数组。

返回值是一个数组,包含三个元素:

  • [0]:图片的 URL。
  • [1]:图片的宽度。
  • [2]:图片的高度。
  • [3](可选):一个布尔值,表示图片是否是缩放的中间版本 (intermediate image)。

如果找不到图片,或者发生其他错误,它会返回 false

二、进入正题:源码剖析

咱们现在就深入 wp-includes/media.php 文件,找到 wp_get_attachment_image_src() 函数的真身。由于 WordPress 的代码会随着版本更新而变化,我这里分析的是 WordPress 6.4.3 版本的代码,但核心逻辑基本不会变。

function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon = false ) {
    $attachment_id = (int) $attachment_id;

    $image = false;
    $size = $size ? $size : 'thumbnail';

    if ( true === $icon ) {
        $post = get_post( $attachment_id );
        if ( $post && 'attachment' === $post->post_type && 'image/' === substr( $post->post_mime_type, 0, 6 ) ) {
            $file = wp_mime_type_icon( $attachment_id );
            if ( $file ) {
                $thumb_url = $file;
                $thumb_width  = 48;
                $thumb_height = 64;
                $is_intermediate = true;
                $image = array( $thumb_url, $thumb_width, $thumb_height, $is_intermediate );
            }
        }
        return $image;
    }

    $image = image_get_intermediate_size( $attachment_id, $size );
    if ( $image ) {
        $thumb_url = $image['url'];
        $thumb_width  = $image['width'];
        $thumb_height = $image['height'];
        $is_intermediate = true;
        $image = array( $thumb_url, $thumb_width, $thumb_height, $is_intermediate );
    }

    if ( ! $image ) {
        $src = wp_get_original_image_path( $attachment_id );
        if ( $src && file_exists( $src ) ) {
            $size = @getimagesize( $src );
            if ( $size ) {
                $thumb_url = wp_get_attachment_url( $attachment_id );
                $thumb_width  = $size[0];
                $thumb_height = $size[1];
                $is_intermediate = false;
                $image = array( $thumb_url, $thumb_width, $thumb_height, $is_intermediate );
            }
        }
    }

    if ( $image ) {
        /**
         * Filters the image data result of an attachment.
         *
         * @since 4.4.0
         *
         * @param array|false $image         Array of image data, or boolean false if no image is available.
         * @param int         $attachment_id Attachment ID.
         * @param string|int[] $size          Requested image size. Can be any registered image size name,
         *                                     or an array of width and height values in pixels (in that order).
         * @param bool        $icon          Whether the image should be treated as an icon.
         */
        $image = apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon );
    }

    return $image;
}

2.1 参数处理和类型转换

$attachment_id = (int) $attachment_id;
$image = false;
$size = $size ? $size : 'thumbnail';
  • 首先,它把 $attachment_id 强制转换为整数,确保类型正确。
  • 然后,初始化 $imagefalse,作为默认返回值。
  • 如果 $size 为空,则默认使用 'thumbnail' 尺寸。

2.2 处理图标(icon)的情况

if ( true === $icon ) {
    $post = get_post( $attachment_id );
    if ( $post && 'attachment' === $post->post_type && 'image/' === substr( $post->post_mime_type, 0, 6 ) ) {
        $file = wp_mime_type_icon( $attachment_id );
        if ( $file ) {
            $thumb_url = $file;
            $thumb_width  = 48;
            $thumb_height = 64;
            $is_intermediate = true;
            $image = array( $thumb_url, $thumb_width, $thumb_height, $is_intermediate );
        }
    }
    return $image;
}
  • 如果 $icon 参数为 true,表示要获取附件的图标。
  • 它会先获取附件的 Post 对象,并检查是否是图片类型的附件。
  • 然后,使用 wp_mime_type_icon() 函数获取图标的 URL。
  • 如果找到了图标,就构建包含 URL、宽度(48px)、高度(64px)和 is_intermediate 标志的数组,并返回。

2.3 尝试获取中间尺寸的图片

$image = image_get_intermediate_size( $attachment_id, $size );
if ( $image ) {
    $thumb_url = $image['url'];
    $thumb_width  = $image['width'];
    $thumb_height = $image['height'];
    $is_intermediate = true;
    $image = array( $thumb_url, $thumb_width, $thumb_height, $is_intermediate );
}
  • 这是最关键的一步。它调用 image_get_intermediate_size() 函数来尝试获取指定尺寸的中间尺寸图片。
  • 如果找到了对应尺寸的图片,就从返回的数组中提取 URL、宽度和高度,并构建最终的 $image 数组。
  • is_intermediate 被设置为 true,表示这是一个中间尺寸的图片(也就是 WordPress 生成的缩略图)。

2.4 如果找不到中间尺寸图片,就获取原始图片

if ( ! $image ) {
    $src = wp_get_original_image_path( $attachment_id );
    if ( $src && file_exists( $src ) ) {
        $size = @getimagesize( $src );
        if ( $size ) {
            $thumb_url = wp_get_attachment_url( $attachment_id );
            $thumb_width  = $size[0];
            $thumb_height = $size[1];
            $is_intermediate = false;
            $image = array( $thumb_url, $thumb_width, $thumb_height, $is_intermediate );
        }
    }
}
  • 如果 image_get_intermediate_size() 返回 false,表示没有找到指定尺寸的图片。
  • 这时,它会尝试获取原始图片的路径,并使用 getimagesize() 函数获取图片的宽度和高度。
  • is_intermediate 被设置为 false,表示这是原始图片。

2.5 应用过滤器

if ( $image ) {
    /**
     * Filters the image data result of an attachment.
     *
     * @since 4.4.0
     *
     * @param array|false $image         Array of image data, or boolean false if no image is available.
     * @param int         $attachment_id Attachment ID.
     * @param string|int[] $size          Requested image size. Can be any registered image size name,
     *                                     or an array of width and height values in pixels (in that order).
     * @param bool        $icon          Whether the image should be treated as an icon.
     */
    $image = apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon );
}

return $image;
  • 在返回结果之前,它会应用一个过滤器 'wp_get_attachment_image_src',允许开发者修改返回的图片数据。这为自定义图片处理提供了很大的灵活性。

三、重点函数解析

上面提到了几个关键的辅助函数,咱们也来简单看看:

  • image_get_intermediate_size( $attachment_id, $size ):这个函数负责从附件的元数据中查找指定尺寸的图片信息。它会检查是否存在对应尺寸的缩略图,如果存在,就返回包含 URL、宽度和高度的数组。如果 $size 是一个数组(包含宽度和高度),它会尝试找到最接近的尺寸。

  • wp_get_original_image_path( $attachment_id ):这个函数获取原始图片的完整服务器路径。它会从附件的元数据中读取 _wp_attached_file 字段,该字段存储了原始图片的相对路径。然后,它会使用 ABSPATH 常量和 wp_upload_dir() 函数来构建完整的服务器路径。

  • wp_get_attachment_url( $attachment_id ):这个函数获取附件的 URL。它会从数据库中读取附件的 guid 字段,该字段存储了附件的 URL。

  • getimagesize( $filename ):这是一个 PHP 内置函数,用于获取图片的尺寸信息。它会返回一个包含宽度、高度和其他信息的数组。

四、流程总结

为了更清晰地理解 wp_get_attachment_image_src() 函数的工作流程,咱们可以用一个流程图来概括:

graph TD
    A[开始] --> B{参数校验和初始化};
    B --> C{icon 参数为 true?};
    C -- 是 --> D[获取图标 URL];
    D --> E[构建图片信息数组];
    E --> F[返回图片信息];
    C -- 否 --> G[尝试获取中间尺寸图片];
    G -- 找到 --> H[构建图片信息数组];
    H --> F;
    G -- 未找到 --> I[获取原始图片路径];
    I -- 找到 --> J[获取原始图片尺寸];
    J --> K[构建图片信息数组];
    K --> F;
    I -- 未找到 --> L[返回 false];
    L --> F;
    F --> M[应用过滤器];
    M --> N[结束];

五、实战演练

说了这么多理论,不如来点实际的。下面是一些使用 wp_get_attachment_image_src() 函数的例子:

5.1 获取缩略图的 URL

$attachment_id = 123; // 附件的 ID
$image_data = wp_get_attachment_image_src( $attachment_id, 'thumbnail' );

if ( $image_data ) {
    $thumbnail_url = $image_data[0];
    echo '<img src="' . esc_url( $thumbnail_url ) . '" alt="Thumbnail">';
} else {
    echo '找不到缩略图';
}

5.2 获取中等尺寸图片的 URL、宽度和高度

$attachment_id = 456; // 附件的 ID
$image_data = wp_get_attachment_image_src( $attachment_id, 'medium' );

if ( $image_data ) {
    $medium_url = $image_data[0];
    $medium_width = $image_data[1];
    $medium_height = $image_data[2];

    echo '<img src="' . esc_url( $medium_url ) . '" width="' . esc_attr( $medium_width ) . '" height="' . esc_attr( $medium_height ) . '" alt="Medium Image">';
} else {
    echo '找不到中等尺寸图片';
}

5.3 获取自定义尺寸图片的 URL

$attachment_id = 789; // 附件的 ID
$image_size = array( 300, 200 ); // 自定义尺寸:宽度 300px,高度 200px
$image_data = wp_get_attachment_image_src( $attachment_id, $image_size );

if ( $image_data ) {
    $custom_url = $image_data[0];
    $custom_width = $image_data[1];
    $custom_height = $image_data[2];

    echo '<img src="' . esc_url( $custom_url ) . '" width="' . esc_attr( $custom_width ) . '" height="' . esc_attr( $custom_height ) . '" alt="Custom Image">';
} else {
    echo '找不到自定义尺寸图片';
}

5.4 使用过滤器自定义图片 URL

function my_custom_image_url( $image, $attachment_id, $size, $icon ) {
    // 在 URL 后面添加一个参数,用于图片追踪
    if ( $image ) {
        $image[0] = add_query_arg( 'utm_source', 'my_theme', $image[0] );
    }
    return $image;
}

add_filter( 'wp_get_attachment_image_src', 'my_custom_image_url', 10, 4 );

六、注意事项

  • 性能优化: 频繁调用 wp_get_attachment_image_src() 可能会影响性能,特别是当获取原始图片时。建议尽量使用预定义的尺寸,并缓存结果。
  • 错误处理: 在使用返回的 URL 之前,一定要进行转义,防止 XSS 攻击。使用 esc_url() 函数可以安全地输出 URL。
  • 图片尺寸: 如果你指定了自定义尺寸,但 WordPress 没有生成对应尺寸的缩略图,它会返回原始图片。
  • 附件 ID: 确保 $attachment_id 是一个有效的附件 ID,否则函数会返回 false

七、总结

wp_get_attachment_image_src() 函数是 WordPress 中一个非常方便的工具,可以帮助你轻松获取媒体附件的图片信息。通过深入了解它的源码,我们可以更好地理解它的工作原理,并灵活地应用它来满足各种需求。

希望今天的讲座对你有所帮助。记住,代码的世界充满了乐趣,只要你敢于探索,就能发现无限的可能。 祝大家编程愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注