问题描述
我想在自定义文件夹中上传自定义图片大小。该文件夹应具有所选宽度的名称。例如:
如果我添加这些自定义尺寸…
add_image_size('custom-1', 300, 9999);
add_image_size('custom-2', 400, 9999);
这将是很好的上传的图像是这样上传的:
http://www.my-site.com/wp-content/uploads/300/my-image.jpg
http://www.my-site.com/wp-content/uploads/400/my-image.jpg
这可能吗?我只发现我可以用 upload_dir 过滤器更改全局上传文件夹。
最佳解决方案
菲利普,任何事情都是可能的,如果你把你的想法。您可以通过扩展 WordPress 图像编辑器类来解决您的问题。
注意我正在使用 WordPress 3.7 – 我没有在早期版本和最新的 3.8 版本中检查下列代码。
图像编辑器基础知识
WordPress 有两个内置的类来处理图像处理:
-
WP_Image_Editor_GD
(/wp-includes/class-wp-image-editor-gd.php
) -
WP_Image_Editor_Imagick
(/wp-includes/class-wp-image-editor-imagick.php
)
这两个类扩展了 WP_Image_Editor
,因为它们都使用不同的图像引擎 (分别为 GD 和 ImageMagick) 来加载,调整大小,压缩和保存图像。
默认情况下,WordPress 将首先尝试使用 ImageMagick 引擎,该引擎需要一个 PHP 扩展,因为它通常优于 PHP 的默认 GD 引擎。大多数共享服务器没有启用 ImageMagick 扩展。
添加图像编辑器
要决定使用哪种引擎,WordPress 会调用内部函数__wp_image_editor_choose()
(位于/wp-includes/media.php
中) 。此函数循环遍历所有引擎,以查看哪个引擎可以处理请求。
该功能还有一个称为 wp_image_editors
的过滤器,可以让您添加更多的图像编辑器,如:
add_filter("wp_image_editors", "my_wp_image_editors");
function my_wp_image_editors($editors) {
array_unshift($editors, "WP_Image_Editor_Custom");
return $editors;
}
请注意,我们预设了自定义图像编辑器类 WP_Image_Editor_Custom
,因此 WordPress 将在测试其他引擎之前检查我们的引擎是否可以处理调整大小。
创建我们的图像编辑器
现在我们要写自己的图像编辑器,所以我们可以自己决定文件名。 Filenaming 由 WP_Image_Editor::generate_filename()
(两个引擎继承此方法) 的方法处理,因此我们应该在我们的自定义类中覆盖。
由于我们只计划更改文件名,所以我们应该扩展现有的引擎之一,所以我们不必重新发明。我将在我的例子中扩展 WP_Image_Editor_GD
,因为您可能没有启用 ImageMagick 扩展。该代码对于 ImageMagick 设置可以互换。如果您计划使用不同设置的主题,您可以添加两者。
// Include the existing classes first in order to extend them.
require_once ABSPATH.WPINC."/class-wp-image-editor.php";
require_once ABSPATH.WPINC."/class-wp-image-editor-gd.php";
class WP_Image_Editor_Custom extends WP_Image_Editor_GD {
public function generate_filename($prefix = NULL, $dest_path = NULL, $extension = NULL) {
// If empty, generate a prefix with the parent method get_suffix().
if(!$prefix)
$prefix = $this->get_suffix();
// Determine extension and directory based on file path.
$info = pathinfo($this->file);
$dir = $info['dirname'];
$ext = $info['extension'];
// Determine image name.
$name = wp_basename($this->file, ".$ext");
// Allow extension to be changed via method argument.
$new_ext = strtolower($extension ? $extension : $ext);
// Default to $_dest_path if method argument is not set or invalid.
if(!is_null($dest_path) && $_dest_path = realpath($dest_path))
$dir = $_dest_path;
// Return our new prefixed filename.
return trailingslashit($dir)."{$prefix}/{$name}.{$new_ext}";
}
}
上面的代码大部分是从 WP_Image_Editor
类直接复制的,并为了方便起见。唯一的实际变化是后缀现在是前缀。
或者,您可以调用 parent::generate_filename()
并使用 mb_str_replace()
将后缀更改为前缀,但我认为更倾向于出错。
保存元数据的新路径
上传 image.jpg
后,uploads 文件夹如下所示:
-
2013/12/150x150/image.jpg
-
2013/12/300x300/image.jpg
-
2013/12/image.jpg
到现在为止还挺好。但是,当调用 wp_get_attachment_image_src()
这样的基本功能时,我们会注意到所有的图像大小都存储为 image.jpg
,而没有新的目录路径。
我们可以通过将新的文件夹结构保存到图像元数据 (存储文件名的位置) 来解决此问题。在插入数据库之前,数据通过各种过滤器 (wp_generate_attachment_metadata
等) 运行,但由于我们已经在实现自定义图像编辑器,因此我们可以回到图像大小元数据源 WP_Image_Editor::multi_resize()
。它生成像这样的数组:
Array (
[thumbnail] => Array (
[file] => image.jpg
[width] => 150
[height] => 150
[mime-type] => image/jpeg
)
[medium] => Array (
[file] => image.jpg
[width] => 300
[height] => 300
[mime-type] => image/jpeg
)
)
我们将在我们的自定义类中覆盖 multi_resize()
方法:
function multi_resize($sizes) {
$sizes = parent::multi_resize($sizes);
foreach($sizes as $slug => $data)
$sizes[$slug]['file'] = $data['width']."x".$data['height']."/".$data['file'];
return $sizes;
}
你可以看到,我没有打扰替换任何代码。我只是调用父方法并让它生成元数据。然后我循环遍历结果数组,并调整每个大小的 file
值。
现在 wp_get_attachment_image_src($att_id, array(300, 300))
返回 2013/12/300x300/image.jpg
。万岁!
最后的想法
我希望这为您提供一个很好的依据。但是,请注意,如果图像小于指定尺寸 (例如,280×300),生成的后缀 (我们的前缀) 和图像尺寸是 280×300,而不是 300×300 。如果你上传了很多较小的图像,你会得到很多不同的文件夹。
一个很好的解决方案是使用大小插件作为文件夹名称 (small
,medium
等),或将代码扩展到圆形大小,直到最接近的首选图像大小。
你注意到你只想使用宽度作为目录名。要警告 – 插件或主题可以生成两个不同的大小,宽度相同但不同的高度。
此外,您可以通过在 「设置」 和 「设置」 下禁用 「将我上传到月份和 year-based 文件夹」 媒体还是进一步操纵 generate_filename
。
希望这可以帮助。祝你好运!
次佳解决方案
@ Robbert 的答案是将 WordPress 生成的替代大小存储在单独的目录中的神圣资源。我的代码也将上传目录更改为./media,所以如果不想要,请确保编辑这些行。这不是第一个海报问题的确切答案,而是为同一个问题提供了一个替代解决方案:
if ( !is_multisite() ) {
update_option( 'upload_path', 'media' ); //to-do: add to options page
define( 'UPLOADS', 'media' ); //define UPLOADS dir - REQUIRED
}
//don't 「Organize my uploads into month- and year-based folders」
update_option( 'uploads_use_yearmonth_folders', '0' ); // to-do: add to options page
//create a custom WP_Image_Editor that handles the naming of files
function tect_image_editors($editors) {
array_unshift( $editors, 'WP_Image_Editor_tect' );
return $editors;
}
add_filter( 'wp_image_editors', 'tect_image_editors' );
require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
class WP_Image_Editor_tect extends WP_Image_Editor_GD {
public function multi_resize($sizes) {
$sizes = parent::multi_resize($sizes);
$media_dir = trailingslashit( ABSPATH . UPLOADS );
foreach($sizes as $slug => $data) {
$default_name = $sizes[ $slug ]['file'];
$new_name = $slug . '/' . preg_replace( '#-d+xd+.#', '.', $data['file'] );
if ( !is_dir( $media_dir . $slug ) ) {
mkdir( $media_dir . $slug );
}
//move the thumbnail - perhaps not the smartest way to do it...
rename ( $media_dir . $default_name, $media_dir . $new_name );
$sizes[$slug]['file'] = $new_name;
}
return $sizes;
}
}
根据我的测试,没有任何问题的工作,虽然我没有试图检查它如何票价与流行的画廊/媒体插件。
相关奖金:一个原始实用程序删除所有 WordPress 生成的缩略图 delete_deprecated_thumbs.php
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。