Moving WordPress’ /wp-content/uploads out of your DocumentRoot

Why might you want to move your /wp-content/uploads folder out of your DocumentRoot? In my case, I use DropBox to sync files between my desktop and my laptop for doing development – no matter where I was working last, my changes, including Subversion status from the hidden .svn directories, are ready to go on the other computer (assuming I have Internet access of course, but even then DropBox will copy over the local network if it’s available, which means it’s pretty quick at home). For some of my site’s, like this one, there are gigabytes and gigabytes of images in my uploads directory, but they don’t really do that much for me in terms of development, but I still need them.

The solution for me was to move the uploads folder outside of the Apache DocumentRoot, were it can still be accessed, but doesn’t count against my DropBox usage (and doesn’t suck up bandwidth syncing thumbnail generation and the like.)

My first order of business was to break uploads out into a different SVN path – otherwise it will just update the folder every time you run an “svn up“. On the production server, you would want to do the following:

# WordPress Files
# https://svn.example.com/mysite/web/trunk
svn co https://svn.example.com/mysite/web/trunk /var/www/mysite/html
# WordPress Uploads
# https://svn.example.com/mysite/uploads/trunk
svn co https://svn.example.com/mysite/uploads/trunk /var/www/mysite/html/wp-content/uploads
# add "uploads" to your svn:ignore in the wp-content folder
svn propedit svn:ignore /var/www/mysite/html/wp-content/
svn up /var/www/mysite/html/wp-content/
svn commit -m "saving svn:ignore for uploads" /var/www/mysite/html/wp-content/

And then on your Workstation, the following:

# WordPress Files
# https://svn.example.com/mysite/web/trunk
svn co https://svn.example.com/mysite/web/trunk ~/Dropbox/MySites/mysite
# WordPress Uploads
# https://svn.example.com/mysite/uploads/trunk
svn co https://svn.example.com/mysite/uploads/trunk  ~/Documents/MySites/mysite

I also added the following rules to /etc/subversion/config on my server and ~/.subversion/config on my workstation to prevent thumbnails from being added – there are lots of ways these can be regenerated if necessary.

[miscellany]
global-ignores = *-[0-9]*x[0-9]*.jpg -[0-9]*x[0-9]*.gif -[0-9]*x[0-9]*.png -[0-9]*x[0-9]*.bmp -[0-9]*x[0-9]*.jpeg

Now in your Apache configuration for your workstation, you need to set an AliasMatch for the uploads directory so that Apache can serve up these files. I use MAMP running as my user, so I don’t have to worry about permissions, but you should keep this in mind depending on your configuration.

<VirtualHost *:80>
    DocumentRoot "/Users/justinsilver/Dropbox/MySites/mysite"
    ServerName local.mysite.com
    
    # Reference the uploads folder in your Documents
    AliasMatch ^/wp-content/uploads/(.*) /Users/justinsilver/Documents/MySites/mysite/wp-content/uploads/$1
    
    <Directory /Users/justinsilver/Dropbox/MySites/mysite>
                AllowOverride All
    </Directory>
</VirtualHost>

With all of this done, you’re good to go as far as serving files, but WordPress will still be confused when it tries to write to the directory, since it uses an absolute path. To fix this, we can use a static defined in wp-config.php (which should be different than production anyway, considering you probably had to set overrides for WP_HOME and WP_SITEURL plus the local database configuration) and use that to selectively change the path to the uploads directory. Thus, add the absolute path to your wp-config.php like so, on the workstation:

define('WP_DEV_UPLOADS', '/Users/justinsilver/Documents/MySites/mysite/wp-content/uploads');

With this set, add the following to your theme’s functions.php, or your functions plugin (more on this at a different time) to hook to the “upload_dir” and change the uploads directory that WordPress uses.

if (defined('WP_DEV_UPLOADS')){
    if (is_dir(WP_DEV_UPLOADS)){
        // use directory outside of Dropbox for uploads so they dont go to Dropbox (uses Alias in VirtualHost)
        function wp_dev_upload_dir($upload_dir){ 
            $upload_dir['path']    = str_replace( $upload_dir['basedir'], WP_DEV_UPLOADS, $upload_dir['path'] );
            $upload_dir['basedir'] = WP_DEV_UPLOADS;
             
            return $upload_dir;
        }
        add_filter('upload_dir', 'wp_dev_upload_dir');
    } else {
        error_log('WP_DEV_UPLOADS is defined but does not exist: ' . WP_DEV_UPLOADS);
    }
}

You may also like...

5 Responses

  1. Xavier F says:

    This is great!
    Is there a way to also make this method work on a WordPress multisite installation?
    I’ve tried to do it and it does not work quite right.

    thanks

  2. Andy says:

    Great! But I have one question: when i upload a filde i can find it on my website but i can’t open it because the permalink is the old one …/uploads/…

    How I can change this?

    Many Thanks!

    • User Avatar Justin Silver says:

      Hi Andy, if these are existing pages/posts and media then you might need to update the actual post content with the new URL. You can do this with a script, or do it dynamically with filters and a bit more effort. Good luck!

  3. Greetings! Very useful advice in this particular post! It is the little changes that make the greatest changes.
    Thanks for sharing!

Leave a Reply

Your email address will not be published. Required fields are marked *