详解 WordPress `wp_generate_attachment_metadata()` 函数的源码:如何生成图片附件的元数据,包括不同尺寸的 URL 和尺寸信息。

各位观众老爷们,晚上好!我是今天的讲座主持人,咱们今儿个来聊聊WordPress里一个神秘又重要的小精灵——wp_generate_attachment_metadata()。这货藏在WordPress的核心深处,专门负责给上传的图片附件生成各种元数据,包括不同尺寸的图片URL,还有它们的尺寸信息。 听起来是不是有点枯燥?别担心,咱们用最通俗易懂的方式,把这小精灵扒个精光,看看它到底是怎么工作的。

一、背景故事:图片背后的秘密

话说,咱们往WordPress上传一张图片,表面上看只是多了个文件而已。但实际上,为了适应各种设备和布局,WordPress会在后台偷偷摸摸地生成一堆不同尺寸的副本。 比如,你上传了一张1920×1080的大图,WordPress可能会自动生成300×200的缩略图,600×400的中等尺寸图,还有1024×768的大尺寸图。 这些图可不是白生成的,它们的存在让你的网站在手机、平板、电脑上都能有最佳的显示效果。而wp_generate_attachment_metadata()就是负责生成这些不同尺寸图片信息并记录下来的关键人物。

二、wp_generate_attachment_metadata():闪亮登场!

这个函数位于wp-includes/media.php文件中。它的主要作用是:

  1. 生成缩略图和各种尺寸的图片。(如果需要)
  2. 获取图片的基本信息,如宽度、高度、文件大小等。
  3. 将这些信息整理成数组,并存储到wp_postmeta表中。

咱们先来看看它的函数原型:

function wp_generate_attachment_metadata( $attachment_id, $file ) {
    // ...各种神秘代码...
    return $metadata;
}
  • $attachment_id:附件的ID,也就是wp_posts表中对应的ID。
  • $file:附件的完整路径,例如/path/to/your/wp-content/uploads/2023/10/image.jpg
  • 返回值:一个包含附件元数据的数组。

三、代码剖析:一步一步揭秘

接下来,咱们一点一点地剖析wp_generate_attachment_metadata()的源码,看看它是如何工作的。

  1. 准备工作:检查和设置

    $attachment_id = (int) $attachment_id;
    $file          = wp_normalize_path( $file );
    
    // Check the file exists.
    if ( ! file_exists( $file ) ) {
        return false;
    }
    
    $metadata = array();

    首先,函数会将$attachment_id转换为整数,并使用wp_normalize_path()标准化文件路径。然后,它会检查文件是否存在。如果文件不存在,直接返回false。最后,初始化一个空数组$metadata,用于存储生成的元数据。

  2. 获取图片信息:让EXIF说话

    $imagesize = getimagesize( $file );
    $mime_type = false;
    
    if ( is_array( $imagesize ) ) {
        $mime_type = $imagesize['mime'];
    }
    
    if ( ! $mime_type ) {
        return false;
    }
    
    $metadata['width']  = $imagesize[0];
    $metadata['height'] = $imagesize[1];
    
    list( $uwidth, $uheight ) = wp_constrain_dimensions( $metadata['width'], $metadata['height'], 128, 96 );
    
    $metadata['hwstring_small'] = "height='$uheight' width='$uwidth'";
    
    $metadata['file'] = wp_basename( $file );

    这里,getimagesize()函数闪亮登场,它可以获取图片的一些基本信息,比如宽度、高度、MIME类型等。如果getimagesize()返回的是一个数组,说明获取信息成功。然后,将宽度和高度存储到$metadata数组中。wp_constrain_dimensions()函数用于限制图片的最大尺寸,这里限制为128×96,用于生成hwstring_small属性,方便前端显示。最后,使用wp_basename()获取文件名,并存储到$metadata['file']中。

  3. 生成不同尺寸的图片:裁剪大师

    $sizes = array();
    
    foreach ( _wp_get_additional_image_sizes() as $size => $size_data ) {
        $sizes[ $size ] = array(
            'width'  => $size_data['width'],
            'height' => $size_data['height'],
            'crop'   => $size_data['crop'],
        );
    }
    
    $intermediate_size = apply_filters( 'intermediate_image_sizes_advanced', $sizes, $attachment_id );
    
    if ( apply_filters( 'image_resize_dimensions', true, $imagesize[0], $imagesize[1], $intermediate_size ) ) {
        $resized = image_make_intermediate_size( $file, $intermediate_size['width'], $intermediate_size['height'], $intermediate_size['crop'] );
    
        if ( $resized ) {
            $metadata['sizes'][ $size ] = $resized;
        }
    }

    这段代码是生成不同尺寸图片的关键。首先,它通过_wp_get_additional_image_sizes()函数获取所有已注册的图片尺寸。这些尺寸通常在主题的functions.php文件中使用add_image_size()函数注册。

    然后,它会遍历这些尺寸,并使用image_make_intermediate_size()函数生成对应尺寸的图片。image_make_intermediate_size()函数会根据指定的宽度、高度和裁剪选项,生成一个新的图片文件,并返回该文件的相关信息,例如文件名、宽度、高度等。

    apply_filters( 'intermediate_image_sizes_advanced', $sizes, $attachment_id ) 这个钩子允许开发者修改需要生成的图片尺寸。开发者可以通过这个钩子添加自定义的尺寸,或者删除不需要的尺寸。

    apply_filters( 'image_resize_dimensions', true, $imagesize[0], $imagesize[1], $intermediate_size )这个钩子允许开发者自定义图片缩放的逻辑。

    让我们深入看一下 image_make_intermediate_size() 函数:

    function image_make_intermediate_size( $file, $width, $height, $crop = false ) {
        $resized_file = image_resize( $file, $width, $height, $crop );
    
        if ( is_wp_error( $resized_file ) ) {
            return false;
        }
    
        $info = getimagesize( $resized_file );
        $resized = array(
            'file'   => wp_basename( $resized_file ),
            'width'  => $info[0],
            'height' => $info[1],
        );
    
        return $resized;
    }

    这个函数调用了 image_resize() 函数来实际执行图片的缩放和裁剪操作。image_resize() 是一个更底层的函数,它会根据 PHP 的 GD 库或 ImageMagick 库来完成图片的缩放和裁剪。 如果 image_resize() 失败,则返回一个 WP_Error 对象,image_make_intermediate_size() 会返回 false。 否则,它会获取缩放后的图片的尺寸信息,并返回一个包含文件名、宽度和高度的数组。

  4. 生成缩略图:特殊待遇

    $thumb_file = wp_get_attachment_thumb_file( $attachment_id );
    
    if ( ! empty( $thumb_file ) && file_exists( $thumb_file ) ) {
        $thumb = getimagesize( $thumb_file );
    
        if ( $thumb ) {
            $metadata['thumb'] = wp_basename( $thumb_file );
        }
    }

    这段代码专门处理缩略图。它首先使用wp_get_attachment_thumb_file()函数获取缩略图的文件路径。如果缩略图文件存在,则获取其尺寸信息,并将文件名存储到$metadata['thumb']中。

  5. 生成 EXIF 元数据

    // fetch additional metadata from exif/iptc.
    $image_meta = wp_read_image_metadata( $file );
    
    if ( $image_meta ) {
        $metadata['image_meta'] = $image_meta;
    }

    此代码段使用wp_read_image_metadata()函数从图像文件中提取EXIF和IPTC元数据。这些数据可以包含相机型号、拍摄日期、地理位置等信息。如果成功提取到元数据,则将其存储在$metadata['image_meta']中。

  6. 优化图片(可选):更小的体积

    /** This filter is documented in wp-includes/media.php */
    $metadata = apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id, $file );
    
    wp_maybe_rotate_exif( $file, $attachment_id, $metadata );
    
    return $metadata;

    在生成元数据之后,wp_generate_attachment_metadata函数会应用wp_generate_attachment_metadata过滤器。 开发者可以使用此过滤器来修改元数据,例如添加自定义字段,或者执行一些额外的处理操作。

    wp_maybe_rotate_exif( $file, $attachment_id, $metadata ); 函数会根据 EXIF 信息自动旋转图片。 某些相机在拍摄照片时会记录照片的方向信息,但默认情况下,WordPress 不会自动旋转照片。 这个函数会读取 EXIF 信息,如果发现照片需要旋转,则会自动旋转照片。

  7. 大结局:存储元数据

    上面已经生成了所有需要的元数据,现在需要将这些数据存储到数据库中。 这通常是通过 wp_update_attachment_metadata() 函数来完成的,但这个函数并不在 wp_generate_attachment_metadata() 函数内部调用。 wp_generate_attachment_metadata() 函数只负责生成元数据,而 wp_update_attachment_metadata() 函数负责将元数据存储到数据库中。

    wp_update_attachment_metadata() 函数的实现非常简单:

    function wp_update_attachment_metadata( $post_id, $metadata ) {
        return update_post_meta( $post_id, '_wp_attachment_metadata', $metadata );
    }

    它只是简单地调用 update_post_meta() 函数,将元数据存储到 _wp_attachment_metadata 这个自定义字段中。

四、元数据结构:一览众山小

那么,wp_generate_attachment_metadata()函数最终返回的$metadata数组到底长什么样呢? 咱们来看一个示例:

Array
(
    [width] => 1920
    [height] => 1080
    [file] => image.jpg
    [sizes] => Array
        (
            [thumbnail] => Array
                (
                    [file] => image-150x150.jpg
                    [width] => 150
                    [height] => 150
                    [mime-type] => image/jpeg
                )

            [medium] => Array
                (
                    [file] => image-300x169.jpg
                    [width] => 300
                    [height] => 169
                    [mime-type] => image/jpeg
                )

            [large] => Array
                (
                    [file] => image-1024x576.jpg
                    [width] => 1024
                    [height] => 576
                    [mime-type] => image/jpeg
                )

            [medium_large] => Array
                (
                    [file] => image-768x432.jpg
                    [width] => 768
                    [height] => 432
                    [mime-type] => image/jpeg
                )

            [1536x1536] => Array
                (
                    [file] => image-1536x864.jpg
                    [width] => 1536
                    [height] => 864
                    [mime-type] => image/jpeg
                )

            [2048x2048] => Array
                (
                    [file] => image-1920x1080.jpg
                    [width] => 1920
                    [height] => 1080
                    [mime-type] => image/jpeg
                )

        )

    [image_meta] => Array
        (
            [aperture] => 2.2
            [credit] =>
            [camera] => iPhone 7
             =>
            [created_timestamp] => 1509484800
            [copyright] =>
            [focal_length] => 2.8
            [iso] => 20
            [shutter_speed] => 0.0076923076923077
            [title] =>
            [orientation] => 1
            [keywords] => Array
                (
                )

        )

)

咱们来解读一下:

  • width:原始图片的宽度。
  • height:原始图片的高度。
  • file:原始图片的文件名。
  • sizes:一个数组,包含了所有生成的图片尺寸的信息。每个尺寸都有file(文件名)、width(宽度)、height(高度)和mime-type(MIME类型)等属性。
  • image_meta:一个数组,包含了图片的EXIF元数据,例如相机型号、拍摄日期、光圈、ISO等。

五、钩子(Filters):扩展的翅膀

wp_generate_attachment_metadata()函数提供了几个重要的钩子,允许开发者自定义其行为。

钩子名称 作用 参数
intermediate_image_sizes_advanced 修改需要生成的图片尺寸。开发者可以通过这个钩子添加自定义的尺寸,或者删除不需要的尺寸。 $sizes (array): 默认的尺寸数组, $attachment_id (int): 附件ID
image_resize_dimensions 自定义图片缩放的逻辑。 true (bool): 是否允许缩放, $orig_w (int): 原始宽度, $orig_h (int): 原始高度, $dest_w (int): 目标宽度, $dest_h (int): 目标高度, $crop (bool): 是否裁剪
wp_generate_attachment_metadata 修改最终生成的元数据。 $metadata (array): 元数据数组, $attachment_id (int): 附件ID, $file (string): 文件路径

六、总结:小精灵的强大力量

wp_generate_attachment_metadata()函数虽然看起来不起眼,但它却是WordPress图片处理的核心。它负责生成不同尺寸的图片,并记录这些图片的信息,使得WordPress能够灵活地适应各种设备和布局。 通过理解wp_generate_attachment_metadata()函数的源码,咱们可以更好地控制WordPress的图片处理流程,并根据自己的需求进行定制。

好了,今天的讲座就到这里。希望大家对wp_generate_attachment_metadata()这个小精灵有了更深入的了解。 感谢大家的观看,咱们下期再见!

发表回复

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