分析 WordPress `wp_get_attachment_image_src()` 函数的源码:如何根据图片尺寸获取 URL 和尺寸信息。

WordPress 图片的秘密:wp_get_attachment_image_src() 深度解析

大家好! 今天咱们来聊聊 WordPress 里一个挺重要的函数:wp_get_attachment_image_src()。这函数看着名字挺长,但作用很简单,就是根据图片 ID 和尺寸,给你返回图片的 URL 和尺寸信息。

可以把它想象成一个图片快递员,你告诉它图片的编号和想要的包装大小,它就能把图片的地址和实际尺寸告诉你。是不是很方便?

那么,这个“快递员”是怎么工作的呢? 咱们一起扒一扒它的源码,看看它到底是怎么找到并处理图片的。

1. 函数概览

首先,我们来看看 wp_get_attachment_image_src() 的基本用法:

<?php
$attachment_id = 123; // 你的图片 ID
$size = 'thumbnail'; // 预定义的尺寸,比如 'thumbnail', 'medium', 'large', 'full',或者一个数组 [width, height]

$image_data = wp_get_attachment_image_src( $attachment_id, $size );

if ( $image_data ) {
  $image_url = $image_data[0]; // 图片 URL
  $image_width = $image_data[1]; // 图片宽度
  $image_height = $image_data[2]; // 图片高度
  $image_is_intermediate = $image_data[3]; // 是否是中间尺寸图片
} else {
  echo '找不到图片!';
}
?>

这个例子展示了最常见的用法。 你提供图片 ID 和尺寸,函数返回一个数组,包含图片的 URL、宽度、高度以及一个布尔值,告诉你这个图片是不是 WordPress 生成的中间尺寸图片。

2. 源码剖析:一步一步揭秘

现在,咱们深入源码,看看 wp_get_attachment_image_src() 到底是怎么实现的。

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

    if ( ! is_int( $attachment_id ) || $attachment_id < 1 ) {
        return false;
    }

    // 1. 获取图片的 metadata
    $image_src = wp_get_attachment_metadata( $attachment_id );

    // 如果 metadata 不存在,说明图片可能损坏或丢失
    if ( empty( $image_src ) ) {
        return false;
    }

    // 2. 处理尺寸参数
    if ( true === $icon ) {
        $file = wp_mime_type_icon( $attachment_id );
        $path = str_replace( wp_basename( $file ), '', $file );
        $width = $height = 36;
    } else {
        if ( is_array( $size ) && 2 === count( $size ) ) {
            // 如果 $size 是一个数组,直接使用数组中的宽度和高度
            $width  = intval( $size[0] );
            $height = intval( $size[1] );
        } elseif ( is_string( $size ) ) {
            // 如果 $size 是一个字符串,从 WordPress 的尺寸配置中查找
            $intermediate_size = image_get_intermediate_size( $attachment_id, $size );
            if ( $intermediate_size ) {
                $width  = $intermediate_size['width'];
                $height = $intermediate_size['height'];
            }
        }

        // 如果找不到对应的尺寸,返回 false
        if ( empty( $width ) || empty( $height ) ) {
            return false;
        }

        // 3. 根据尺寸查找图片文件
        $file = wp_get_attachment_image_file( $attachment_id, $width, $height );

        // 如果找不到对应的文件,返回 false
        if ( empty( $file ) ) {
            return false;
        }

        // 4. 获取图片的 URL
        $url = wp_get_attachment_url( $attachment_id );

        // 5. 检查是否是中间尺寸图片
        $is_intermediate = ( empty( $image_src['original_image'] ) || ( (string) $width !== (string) $image_src['width'] ) || ( (string) $height !== (string) $image_src['height'] ) );
    }

    // 6. 构建返回结果
    if ( ! empty( $url ) && ! empty( $width ) && ! empty( $height ) ) {
        $image = array( $url, $width, $height, $is_intermediate );
    }

    return $image;
}

咱们把上面的代码拆解成几个关键步骤,详细分析:

第一步:参数验证和初始化

$image = false;
$attachment_id = (int) $attachment_id;

if ( ! is_int( $attachment_id ) || $attachment_id < 1 ) {
    return false;
}
  • 首先,函数初始化 $imagefalse,这是默认的返回值,表示没有找到合适的图片。
  • 然后,将传入的 $attachment_id 强制转换为整数,确保参数类型正确。
  • 接着,进行参数验证,确保 $attachment_id 是一个有效的正整数。如果不是,直接返回 false

第二步:获取图片的 Metadata

$image_src = wp_get_attachment_metadata( $attachment_id );

if ( empty( $image_src ) ) {
    return false;
}
  • wp_get_attachment_metadata() 函数是关键,它负责从数据库中获取图片的元数据(metadata)。元数据包含了图片的各种信息,比如文件路径、尺寸、EXIF 信息等等。
  • 如果获取到的 $image_src 为空,说明该图片可能损坏或丢失,函数直接返回 false

第三步:处理尺寸参数

这部分代码比较复杂,因为它需要处理各种不同的 $size 参数:

  • $icon = true: 如果 $icon 参数为 true,说明要获取的是附件的图标。 这时,函数会调用 wp_mime_type_icon() 获取图标的文件路径,并设置宽度和高度为 36。

    if ( true === $icon ) {
      $file = wp_mime_type_icon( $attachment_id );
      $path = str_replace( wp_basename( $file ), '', $file );
      $width = $height = 36;
    }
  • $size 是数组: 如果 $size 是一个包含两个元素的数组,比如 [100, 200],那么数组的第一个元素就是宽度,第二个元素就是高度。

    if ( is_array( $size ) && 2 === count( $size ) ) {
      $width  = intval( $size[0] );
      $height = intval( $size[1] );
    }
  • $size 是字符串: 如果 $size 是一个字符串,比如 'thumbnail''medium',那么函数会调用 image_get_intermediate_size() 来查找对应的宽度和高度。image_get_intermediate_size() 会从 WordPress 的设置中查找预定义的尺寸信息。

    elseif ( is_string( $size ) ) {
      $intermediate_size = image_get_intermediate_size( $attachment_id, $size );
      if ( $intermediate_size ) {
        $width  = $intermediate_size['width'];
        $height = $intermediate_size['height'];
      }
    }
  • 尺寸校验: 如果经过上述处理,仍然没有获取到宽度和高度,说明传入的 $size 参数无效,函数返回 false

    if ( empty( $width ) || empty( $height ) ) {
      return false;
    }

第四步:查找图片文件

$file = wp_get_attachment_image_file( $attachment_id, $width, $height );

if ( empty( $file ) ) {
    return false;
}
  • wp_get_attachment_image_file() 函数负责根据图片 ID、宽度和高度,找到对应的图片文件。 这个函数会考虑 WordPress 生成的各种中间尺寸图片,并尝试找到最匹配的文件。
  • 如果找不到对应的文件,函数返回 false

第五步:获取图片的 URL

$url = wp_get_attachment_url( $attachment_id );
  • wp_get_attachment_url() 函数负责获取图片的 URL。 这个函数会根据 WordPress 的配置,返回图片的完整 URL。

第六步:检查是否是中间尺寸图片

$is_intermediate = ( empty( $image_src['original_image'] ) || ( (string) $width !== (string) $image_src['width'] ) || ( (string) $height !== (string) $image_src['height'] ) );
  • 这部分代码用于判断返回的图片是否是 WordPress 生成的中间尺寸图片。
  • 判断依据是:如果图片的元数据中没有 original_image 字段,或者返回的宽度和高度与原始图片的宽度和高度不一致,那么就认为是中间尺寸图片。

第七步:构建返回结果

if ( ! empty( $url ) && ! empty( $width ) && ! empty( $height ) ) {
    $image = array( $url, $width, $height, $is_intermediate );
}

return $image;
  • 最后,如果成功获取到了 URL、宽度和高度,函数会将这些信息封装到一个数组中,并返回。
  • 数组的结构如下:

    索引 含义 数据类型
    0 图片 URL string
    1 图片宽度 int
    2 图片高度 int
    3 是否是中间尺寸图片 bool

3. 辅助函数:幕后英雄

wp_get_attachment_image_src() 的实现中,有几个辅助函数起着关键作用:

  • wp_get_attachment_metadata(): 负责从数据库中获取图片的元数据。
  • image_get_intermediate_size(): 负责根据尺寸名称(比如 'thumbnail')查找对应的宽度和高度。
  • wp_get_attachment_image_file(): 负责根据图片 ID、宽度和高度,找到对应的图片文件。
  • wp_get_attachment_url(): 负责获取图片的 URL。

这些函数各司其职,共同完成了图片信息的查找和处理。

4. 尺寸的秘密:image_get_intermediate_size()

image_get_intermediate_size() 函数是处理尺寸参数的关键。 让我们看看它的源码:

function image_get_intermediate_size( $attachment_id, $size = 'thumbnail', $calc = true ) {
    global $_wp_additional_image_sizes;

    $imagedata = wp_get_attachment_metadata( $attachment_id );

    if ( ! $imagedata ) {
        return false;
    }

    if ( is_array( $size ) ) {
        return false;
    }

    // Look for registered sizes first.
    if ( isset( $_wp_additional_image_sizes[ $size ]['width'] ) && isset( $_wp_additional_image_sizes[ $size ]['height'] ) ) {
        $width  = intval( $_wp_additional_image_sizes[ $size ]['width'] );
        $height = intval( $_wp_additional_image_sizes[ $size ]['height'] );
        $crop   = $_wp_additional_image_sizes[ $size ]['crop'];
    } else {
        // Standard sizes.
        if ( 'thumbnail' == $size ) {
            $width  = intval( get_option( 'thumbnail_size_w' ) );
            $height = intval( get_option( 'thumbnail_size_h' ) );
            $crop   = (bool) get_option( 'thumbnail_crop' );
        } elseif ( 'medium' == $size ) {
            $width  = intval( get_option( 'medium_size_w' ) );
            $height = intval( get_option( 'medium_size_h' ) );
            $crop   = false;
        } elseif ( 'medium_large' == $size ) {
            $width  = intval( get_option( 'medium_large_size_w' ) );
            $height = intval( get_option( 'medium_large_size_h' ) );
            $crop   = false;
        } elseif ( 'large' == $size ) {
            $width  = intval( get_option( 'large_size_w' ) );
            $height = intval( get_option( 'large_size_h' ) );
            $crop   = false;
        } else {
            return false;
        }
    }

    if ( $calc ) {
        $file = wp_get_attachment_image_file( $attachment_id, $width, $height );
        if ( ! $file ) {
            return false;
        }
    }

    return array(
        'width'  => intval( $width ),
        'height' => intval( $height ),
        'crop'   => $crop,
    );
}

这个函数首先检查 $size 是否是一个已经注册的尺寸。 WordPress 允许主题和插件注册自定义的图片尺寸,这些尺寸信息存储在全局变量 $_wp_additional_image_sizes 中。

如果 $size 不是一个已注册的尺寸,函数会检查它是否是 WordPress 预定义的尺寸,比如 'thumbnail''medium''large' 等。 这些尺寸的宽度和高度存储在 WordPress 的选项中,函数会从选项中读取这些值。

如果 $size 既不是已注册的尺寸,也不是预定义的尺寸,函数会返回 false

5. 文件查找的艺术:wp_get_attachment_image_file()

wp_get_attachment_image_file() 函数负责根据图片 ID、宽度和高度,找到对应的图片文件。 这部分逻辑比较复杂,因为它需要考虑各种情况:

  • 原始图片: 首先,函数会尝试找到原始图片,如果原始图片的宽度和高度与传入的宽度和高度一致,那么就返回原始图片。
  • 中间尺寸图片: 如果找不到原始图片,函数会尝试找到最接近传入宽度和高度的中间尺寸图片。 WordPress 会根据配置生成各种中间尺寸的图片,函数会遍历这些图片,找到最匹配的一个。
  • 缩放: 如果找不到完全匹配的图片,函数可能会对原始图片进行缩放,生成一个新的图片文件。

由于这部分代码比较复杂,就不在这里贴出完整的源码了。 但是,理解了 wp_get_attachment_image_file() 的基本原理,就能更好地理解 wp_get_attachment_image_src() 的工作方式。

6. 缓存的奥秘

为了提高性能,wp_get_attachment_image_src() 函数使用了缓存。 具体来说,函数会将图片的信息缓存到内存中,下次再请求相同的图片时,可以直接从缓存中读取,而不需要再次查询数据库和查找文件。

WordPress 使用对象缓存 API 来实现缓存。 对象缓存 API 允许插件和主题将数据存储到内存中,以便快速访问。

7. 总结

wp_get_attachment_image_src() 函数是 WordPress 中一个非常重要的函数,它负责根据图片 ID 和尺寸,获取图片的 URL 和尺寸信息。

咱们来总结一下:

  1. 参数验证和初始化: 确保传入的参数有效。
  2. 获取 Metadata: 从数据库中获取图片的元数据。
  3. 处理尺寸参数: 处理不同的 $size 参数,获取宽度和高度。
  4. 查找图片文件: 根据图片 ID、宽度和高度,找到对应的图片文件。
  5. 获取 URL: 获取图片的 URL。
  6. 检查是否是中间尺寸图片: 判断返回的图片是否是中间尺寸图片。
  7. 构建返回结果: 将图片信息封装到一个数组中,并返回。

通过深入分析 wp_get_attachment_image_src() 的源码,我们可以更好地理解 WordPress 是如何处理图片的,以及如何根据不同的尺寸获取对应的图片信息。 这对于开发 WordPress 主题和插件来说,是非常有帮助的。

希望今天的讲解对大家有所帮助!下次再见!

发表回复

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