WordPress默认情况下会给上传的每一张图片都生成几个不同大小的缩略图,一般情况下问题不大,但是如果存在短时间上传大量图片的场景,会导致服务器整体卡顿。
这个问题也很好解决,直接将生成缩略图任务扔进队列慢慢处理就好了,毕竟加载/使用缩略图使用也不是很着急的事情,不必在上传完的时候就直接生成出来。
考虑实现一个插件,上传图片成功后将缩略图生成任务扔进任务队列,然后由队列来逐步执行。唯一的问题是WordPress原生是没有任务队列集成的,不过官方也提供了一个任务队列插件Action Scheduler,那这件事情就简单了。
1. 安装Action Scheduler
2. 关闭上传过程中的缩略图生成
翻了翻WordPress的文档,可以通过`intermediate_image_sizes_advanced`这个钩子来实现,直接返回一个空数组,上传时就不会生成缩略图了。
// 禁用默认的缩略图生成
add_filter( 'intermediate_image_sizes_advanced', function () {
return [];
} );
3. 上传成功后,将缩略图生成任务放进任务队列。
// 添加上传后的钩子,将生成缩略图任务加入到Action Scheduler队列中
add_action('add_attachment', function ($attachment_id) {
as_schedule_single_action(
time(),
'generate_thumbnails_for_attachment',
[
'attachment_id' => $attachment_id
],
'ianzhi-thumbnail-optimise'
);
});
4. 缩略图生成任务钩子。
// 辅助函数:获取指定尺寸的具体设置
function image_get_size($attachment_id, $size) {
global $_wp_additional_image_sizes;
$width = get_option("{$size}_size_w");
$height = get_option("{$size}_size_h");
$crop = (bool) get_option("{$size}_crop");
if (isset($_wp_additional_image_sizes[$size])) {
$width = $_wp_additional_image_sizes[$size]['width'];
$height = $_wp_additional_image_sizes[$size]['height'];
$crop = $_wp_additional_image_sizes[$size]['crop'];
}
return array(
'width' => $width,
'height' => $height,
'crop' => $crop
);
}
// 定义缩略图生成任务
add_action('generate_thumbnails_for_attachment', function ($attachment_id) {
// 获取附件元数据
$metadata = wp_get_attachment_metadata($attachment_id);
if (!$metadata) return;
require_once(ABSPATH . 'wp-admin/includes/image.php');
// 获取WordPress中所有已注册的图像尺寸
$sizes = get_intermediate_image_sizes();
foreach ($sizes as $size) {
// 获取每个尺寸的具体设置(宽度、高度、裁剪)
$size_array = image_get_size($attachment_id, $size);
if (!$size_array) continue; // 如果获取失败,跳过这个尺寸
// 生成对应尺寸的缩略图
$resized = image_make_intermediate_size(
get_attached_file($attachment_id),
$size_array['width'],
$size_array['height'],
$size_array['crop']
);
if ($resized) {
// 将新生成的缩略图信息添加到元数据中
$metadata['sizes'][$size] = $resized;
}
}
// 更新附件的元数据
wp_update_attachment_metadata($attachment_id, $metadata);
}, 10, 1);