自定义上传目录中的每个自定义图像大小?

时间:2013-12-08 作者:Philipp Kühn

我想在自定义文件夹中上载自定义图像大小。文件夹应具有选定宽度的名称。例如:

如果我添加这些自定义尺寸。。。

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 滤器

5 个回复
最合适的回答,由SO网友:Robbert 整理而成

菲利普,只要你下定决心,一切皆有可能。您可以通过扩展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;
}
注意,我们prepending 我们的自定义图像编辑器类WP_Image_Editor_Custom 所以WordPress将在测试其他引擎之前检查我们的引擎是否可以处理大小调整。


创建图像编辑器现在我们要编写自己的图像编辑器,这样我们就可以自己决定文件名了。文件命名由方法处理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, 上载文件夹如下所示:

  • 2013/12/150x150/image.jpg
  • 2013/12/300x300/image.jpg
  • 2013/12/image.jpgwp_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. 好极了


    最后的想法

    我希望这为您的详细阐述提供了良好的基础。但是,请注意,如果图像小于指定大小(例如280x300),则生成的后缀(在本例中为前缀)和图像大小为280x300,而不是300x300。如果你上传很多较小的图片,你会得到很多不同的文件夹。

    一个好的解决方案是使用size slug作为文件夹名称(small, medium, 等等)或将代码扩展到四舍五入大小,直到最接近的首选图像大小。

    您注意到只想使用宽度作为目录名。但要注意的是,插件或主题可能会生成两种不同的大小,宽度相同,高度不同。

    此外,您还可以通过在“设置”>“媒体”下禁用“将上载内容组织到基于月份和年份的文件夹”或通过操纵generate_filename 更进一步。

    希望这有帮助。祝你好运

SO网友:Arty2

@Robbert的回答是我努力将WordPress生成的备用大小存储在不同的目录中的一个神圣资源。我的代码还将上载目录更改为/因此,如果您不想编辑这些行,请确保编辑这些行。这并不是第一张海报问题的确切答案,但为同一个问题提供了另一种解决方案:

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+x\\d+\\.#\', \'.\', $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

SO网友:IORoot

答案“robbert”是一个非常棒的答案。然而,它有点过时(我使用的是WordPress 5.7),我想做完全相同的事情,所以这里有一个稍微更新的答案,附带一些额外内容:

我使用了段塞大小而不是尺寸,因为这有点干净,我想从@robert代码中演示一下我将它们作为插件放在同一个文件中。

添加两个新编辑器

/**
 * Add custom image editor (which extends the GD / IMagick editor)
 */
add_filter("wp_image_editors", "my_wp_image_editors");
function my_wp_image_editors($editors) {
    array_unshift($editors, "WP_Image_Editor_Custom_GD");
    array_unshift($editors, "WP_Image_Editor_Custom_IM");
    return $editors;
}

GD类扩展

/**
 * If GD Library being used. (default)
 */
class WP_Image_Editor_Custom_GD extends WP_Image_Editor_GD {



    /**
     * Add the folder prefix before saving to the database and generating
     */
    function multi_resize($sizes) {

        $sizes = parent::multi_resize($sizes);
    
        foreach($sizes as $slug => $data)
            // $sizes[$slug][\'file\'] = $data[\'width\']."x".$data[\'height\']."/".$data[\'file\'];  // creates a /320x300/ folder.
            $sizes[$slug][\'file\'] = $slug."/".$data[\'file\']; // creates a /large/ folder.
    
        return $sizes;
    }



    /**
     * Changes the suffix (300x300) to a directory prefix.
     */
    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\'];

        $sizes  = wp_get_registered_image_subsizes();
        $dimen  = explode(\'x\', $prefix);
        foreach($sizes as $name => $size)
        {
            if ($dimen[0] == $size[\'width\']){
                $prefix = $name;
            }
        }

        // 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}";
    }

}

IMagick类扩展

/**
 * If Imagemagick is being used.
 */
class WP_Image_Editor_Custom_IM extends WP_Image_Editor_Imagick {



    /**
     * Add the folder prefix before saving to the database and generating
     */
    function multi_resize($sizes) {

        $sizes = parent::multi_resize($sizes);
    
        foreach($sizes as $slug => $data)
            // $sizes[$slug][\'file\'] = $data[\'width\']."x".$data[\'height\']."/".$data[\'file\'];  // creates a /320x300/ folder.
            $sizes[$slug][\'file\'] = $slug."/".$data[\'file\']; // creates a /large/ folder.
    
        return $sizes;
    }




    /**
     * Changes the suffix (300x300) to a directory prefix.
     */
    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();


        $sizes  = wp_get_registered_image_subsizes();
        $dimen  = explode(\'x\', $prefix);
        foreach($sizes as $name => $size)
        {
            if ($dimen[0] == $size[\'width\']){
                $prefix = $name;
            }
        }

        // 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}";
    }


}

更新附件元数据

/**
 * We need to rewrite the post attachment metadata so that 
 * we include the new /slug/ directory. This is so we are able to 
 * delete / edit the thumbnail correctly.
 * 
 * see function wp_get_attachment_metadata() in wp-include/post.php
 * 
 */
add_filter(\'wp_get_attachment_metadata\', \'include_slug_in_attachment_size\', 10, 2);

function include_slug_in_attachment_size($data, $attachment_id)
{
    // Add the size slug to the front of the filename.
    foreach($data[\'sizes\'] as $name => $size)
    {
        $file = $data[\'sizes\'][$name][\'file\'];
        $data[\'sizes\'][$name][\'file\'] = $name .\'/\'.$file;
    }

    return $data;
}

现在,将在uploads文件夹中创建具有媒体大小名称的子目录,例如。/uploads/photo.jpg 将会有/uploads/thumbnail/photo.jpg, /uploads/medium/photo.jpg, 等但不仅如此,删除也会删除这些附件。(另外,如果文件夹变为空,也将被删除)。

代码链接到插件:Github - IORoot

详细信息-无需阅读。对于好奇的人,删除流程如下:

  1. post.php 将运行wp_delete_attachment() 功能
  2. 该函数将运行以下行:
$meta = wp_get_attachment_metadata( $post_id );
  1. wp_get_attachment_metadata 中的函数post.php 将运行wp_get_attachment_metadata 过滤器$data[\'sizes\'] 数组并将其返回$data 数组传回集合$meta 在里面wp_delete_attachment().
  2. $meta 然后在wp_delete_attachment() 函数,在线:
wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file );
  1. wp_delete_attachment_files() 函数将使用此$meta 带有foreach() 循环遍历大小并删除每个文件名(我们将其更新为包含slug目录)
    // Remove intermediate and backup images if there are any.
    if ( isset( $meta[\'sizes\'] ) && is_array( $meta[\'sizes\'] ) ) {
        $intermediate_dir = path_join( $uploadpath[\'basedir\'], dirname( $file ) );

        foreach ( $meta[\'sizes\'] as $size => $sizeinfo ) {
            $intermediate_file = str_replace( wp_basename( $file ), $sizeinfo[\'file\'], $file );

            if ( ! empty( $intermediate_file ) ) {
                $intermediate_file = path_join( $uploadpath[\'basedir\'], $intermediate_file );

                if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) {
                    $deleted = false;
                }
            }
        }
    }
就这样。这将看到更新的$sizes 阵列(在$meta) 更新日期:

\'sizes => 
    \'large\' =>
        [
          \'file\' => \'photo.jpg\',
          \'width\' => \'800\',
          \'height\' => \'800\',
          \'mimetype\' => \'image/jpeg\',
        ],
    \'medium\' =>
        [
          \'file\' => \'photo.jpg\',
          \'width\' => \'640\',
          \'height\' => \'640\',
          \'mimetype\' => \'image/jpeg\',
        ],
...
成为:

\'sizes => 
    \'large\' =>
        [
          \'file\' => \'large/photo.jpg\',
          \'width\' => \'800\',
          \'height\' => \'800\',
          \'mimetype\' => \'image/jpeg\',
        ],
    \'medium\' =>
        [
          \'file\' => \'medium/photo.jpg\',
          \'width\' => \'640\',
          \'height\' => \'640\',
          \'mimetype\' => \'image/jpeg\',
        ],
...

SO网友:Krzysiek Dróżdż

我已经看过WordPress代码的这些部分,恐怕没有什么好消息。

共有2类:

  • WP_Image_Editor_GD
  • WP_Image_Editor_Imagick,
两个扩展摘要WP_Image_Editor

这些类正在实现multi_resize 方法,用于从上载的图像生成多个图像。

真正坏的消息是,这里没有过滤器挂钩,我们可以用它来修改新创建文件的目标路径。

SO网友:Philipp Kühn

好的,我想我明白了!不是很完美,但我想要它。对我来说,只有图像的宽度才重要。身高对我没用。特别是为了实施Imager.js 图像url中的高度令人不安。

add_filter(\'image_make_intermediate_size\', \'custom_rename_images\');

function custom_rename_images($image) {
    // Split the $image path
    $info = pathinfo($image);
    $dir = $info[\'dirname\'] . \'/\';
    $ext = \'.\' . $info[\'extension\'];
    $name = wp_basename($image, \'$ext\');

    // New Name
    $name_prefix = substr($name, 0, strrpos($name, \'-\'));
    $size_extension = substr($name, strrpos($name, \'-\') + 1);
    $image_sizes = explode(\'x\', $size_extension);
    $image_width = $image_sizes[0];
    $new_name = $dir . $image_width . \'-\' . $name_prefix . $ext;

    // Rename the intermediate size
    $did_it = rename($image, $new_name);

    // Return if successful
    if ($did_it) return $new_name;

    // Return on fail
    return $image;
}
使用此代码,文件名如下:

http://www.my-site.com/wp-content/uploads/300-my-image.jpg
http://www.my-site.com/wp-content/uploads/400-my-image.jpg
它是not 可以将子文件夹添加到文件名中,因为如果我在帖子/页面中添加图像,将始终使用原始源文件。删除时删除这些图像也不起作用。我不知道为什么。

结束

相关推荐

Adding Relevant Post Images

我想在每个帖子页面的末尾添加相关帖子with an image 在我新创建的网站中http://www.techberita.com但作为一个初学者,这对我来说是一个很大的问题,因为我不能做到这一点,因为我对PHP和wordpress没有太多的知识。我搜索了一些插件,但没有找到一个好的插件。我希望很快得到答复。最好使用php代码。