Bug with moving uploads folder

Seems I've run into a bug in WordPress, which is related to the wp-content/uploads directory. Although I will not claim that this is a bug, but the logic is definitely missing...

Let's deal with it in order. I have an old site from WP 2+. When I created it, I had moved folder uploads to the root of the site. To do this, I defined the constant in wp-config.php:

// this means that the folder ``uploads'' should be in the root of the site
define( 'UPLOADS', 'uploads' );

I also renamed the content folder from wp-content to content. To do this, I defined constants in the same wp-config.php:

define( 'WP_CONTENT_DIR', $_SERVER['DOCUMENT_ROOT'].'/content' );
define( 'WP_CONTENT_URL', 'http://'. $_SERVER['HTTP_HOST'] .'/content' );

Everything worked until recently...

I recently moved the WordPress core to a separate wp folder - that's handy. Now, got this: the WP core is in the wp folder; plugins, etc. in content folder; files in uploads folder and all this in the root of the site.

In WordPress you can logically separate content files (wp-content) and core files (wp-includes, wp-admin, ...). This sets up 2 different URLs in the settings: the Site address and the WordPress address:

After moving the WordPress core, I have pictures missing from my media library. Looking at the URL of the images I saw that the URL had changed from /uploads to /wp/uploads without changing the previously set constant UPLOADS.

Looking into the code of _wp_upload_dir() (this function is the basis for getting all links to files), I saw that the URL builds from the UPLOADS constant and siteurl option, but the path builds as follows: ABSPATH . UPLOADS.

if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option('ms_files_rewriting' ) ) ) {
	$dir = ABSPATH . UPLOADS;
	$url = trailingslashit( $siteurl ) . UPLOADS;
}

This means that the basis is not the root of the site, but the folder where WordPress core is, and if it is a subdirectory, then UPLOADS will refer to this directory. It's not logical, because uploads files it's a site content, but not site engine!

OK, since we can not define a UPLOADS constant so that uploaded files "look at" the root of the site, but not the root of the engine, then we need to delete. And I deleted the UPLOADS constant from wp-config.php, and then moved the folder uploads in the content folder - content.

As a result, the overall structure became the following:

/wp/wp-admin
/wp/wp-includes
/content
/content/uploads

Next, to see if everything was working as it should, I tried uploading the picture to the media library, but the picture was not uploaded to the expected folder: /content/uploads/..., but in the same subfolder of the engine: /wp/uploads/....

Investigation showed that in WP settings the option upload_path is set, which since versions 3.0 is not obligatory and is not set by default. And I had the same uploads value there that I had once set in the UPLOADS constant.

To solve the problem, I simply removed the upload_path option. Replaced all the old links in the content with new ones.To do this, I ran this SQL query:

UPDATE wp_posts SET post_content = REPLACE (post_content, 'http://example.com/uploads/', 'http://example.com/content/uploads/');

And just in case I rebuild all the values of the guid fields of attachments, for this I made a mini-plugin.

What's this all about?

The point is that if you happen to be moving the WordPress base folders on your old site, you need to go to all options page: http://YOURSITE/wp-admin/options.php and check if you have upload_path and ``upload_url_path``` options, they are 99% unnecessary since WP 3.0+ and can be simply removed.

In those cases when you need them, you're more likely to know all about it and this article won't be of interest to you smile

Also, don't try to move the uploads folder outside the content folder (default wp-contents). You won't be able to do that if WP engine files is put in a separate directory. Or it will cause problems if you puts the engine files in a separate folder in the future.

I mentioned above that options are no needed 99% of the time, but there is a 1% when the upload_url_path option is needed - that's when we have multisite enabled and we moved the content folder or the WP core. In both cases we have to set the WP_CONTENT_URL constant. Next, when we switch in one network blog to another using switch_to_blog(). We catch the bug because in many functions, such as getting the URL of an image (see wp_get_attachment_url() and _wp_upload_dir() WP uses WP_CONTENT_URL constant, and it will refer to the current blog, not the one you switched to. This is where the upload_url_path option is needed, because its value is checked first and only then the constant is used if the option is empty.

I will pay more attention to the fact that URL to the uploaded files, even if the WP_CONTENT_URL constant is set, is still working when switching to another blog. Only the domain of this URL will be primary, not of the current site to which we have switched.