I've followed the accepted answer in this question to generate my thumbnails in a custom way.

I extended the image editor class as:

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().
            $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}";
function multi_resize($sizes) {
    $sizes = parent::multi_resize($sizes);
    //This will generate proper metadata for thumbnails
    foreach($sizes as $slug => $data)
        $sizes[$slug]['file'] = $slug."/".$data['file'];

    return $sizes;

Now, original uploads will be stored in uploads and the thumbnails will be stored in uploads/thumbnail/, /uploads/medium/ and uploads/large/.

What i want is one of these 2 scenarios:

1- to store original uploads in a subfolder such as uploads/original and the thumbnails in uploads/thumbnail/, /uploads/medium/ and uploads/large/.

2- to store the original images in uploads/ and the thumbnails in a folder named thumbs/, OUTSIDE the upload directory, in the root.

I was able to achieve number 2, However, when i call a function such as wp_get_attachment_image_src() it will append my custom thumbnail link (stored in post metadata) to the upload directory, producing a link like:


The correct format must be like:


Is it possible to overwrite the metadata while being called to point to the proper file??

2 Answers 2


It appears that the thumbnail URLs are generated relatively to the upload folder. So trying to store them outside the uploads folder is not going to be a good idea.

There are hacks to filter the output for functions such as the_post_thumbnail_url(), but considering side issues such as the thumbnails not being able to be deleted, it's not worth a try.

What i was able to achieve, is to store the generated thumbnails in a different subdirectory, inside the uploads folder, and then protect the original uploads folder by setting the proper rules in the .htaccess file, in case you want to protect them from the visitor, making them forbidden to be accessed directly.

I was able to make a copy of the original generator class in wp-image-editor-gd.php to store the thumbnails in subdirectory. Here is how to do so:

First, we set our own class as the primary image generator:

add_filter('wp_image_editors', 'custom_wp_image_editors');
function custom_wp_image_editors($editors) {
    array_unshift($editors, "custom_WP_Image_Editor");
    return $editors;

We then include the necessary classes to be extended:

require_once ABSPATH . WPINC . "/class-wp-image-editor.php";
require_once ABSPATH . WPINC . "/class-wp-image-editor-gd.php";

And finally setting the path:

class custom_WP_Image_Editor extends WP_Image_Editor_GD {
    public function generate_filename($suffix = null, $dest_path = null, $extension = null) {
        // $suffix will be appended to the destination filename, just before the extension
        if (!$suffix) {
            $suffix = $this->get_suffix();
        $dir = pathinfo($this->file, PATHINFO_DIRNAME);
        $ext = pathinfo($this->file, PATHINFO_EXTENSION);
        $name = wp_basename($this->file, ".$ext");
        $new_ext = strtolower($extension ? $extension : $ext );
        if (!is_null($dest_path) && $_dest_path = realpath($dest_path)) {
            $dir = $_dest_path;
        //we get the dimensions using explode
        $size_from_suffix = explode("x", $suffix);
        return trailingslashit( $dir ) . "{$size_from_suffix[0]}/{$name}.{$new_ext}";

Now the thumbnails will be stored in different sub-folders, based on their width. For example:


And so on.

Possible issue

Now there might be an issue when we upload images smaller than the smallest thumbnail size. For example if we upload an image, sized 100x100pixels while the smallest thumbnail size is 150x150, another folder will be created in the uploads directory. This might result in a lot of subdirectories in the uploads directory. I have solved this issue with another approach, in this question.


2- to store the original images in uploads/ and the thumbnails in a folder named thumbs/, OUTSIDE the upload directory, in the root.

Following your second scenario since you're already halfway through it. You can use the following :

        add_filter( 'wp_get_attachment_image_src', function ( $image, $attachment_id, $size ) {

        // Make sure $image is not false.
        if ( $image ) {
            switch ( $size ) {
                // Add your custom sizes as cases here.
                case 'thumbnail':
                case 'medium':
                case 'large':
                case 'mysize':
                     * This will simply convert the link from
                    only for thumbnails not for original images.
                    $image[0] = str_replace( '/uploads/', '/', $image[0] );

        return $image;
    }, 10, 3 );

I hope that helps you.

  • Thank you. Does this code apply while calling the function or while saving the thumbnails? because i added it to my functions.php and nothing changed.
    – Johansson
    Commented Feb 10, 2017 at 13:36
  • This code will change the image source URL whenever the wp_get_attachment_image_src() function is used to get the image thumbnails. Commented Feb 10, 2017 at 13:59
  • My bad, the array index was incorrect it should be $image[0] instead if $image['src'] Commented Feb 10, 2017 at 14:00
  • Your most welcome! :) Commented Feb 10, 2017 at 14:05
  • Is the answer for other question not working? Please close this question and continue to the other question to prevent unnecessary comments here. Commented Feb 10, 2017 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.