Skip to content

Instantly share code, notes, and snippets.

@maciejbis
Last active March 15, 2024 01:04
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save maciejbis/31df76d3ca03c92166f7efcf1a9a425f to your computer and use it in GitHub Desktop.
Save maciejbis/31df76d3ca03c92166f7efcf1a9a425f to your computer and use it in GitHub Desktop.
Rewrite Wordpress uploads URLs
<?php
/*
* Plugin Name: Rewrite Wordpress uploads URLs
* Plugin URI: https://permalinkmanager.pro?utm_source=plugin
* Description: Replace /wp-content/uploads/YYYY/MM/ with different directory
* Version: 1.0.0
* Author: Maciej Bis
* Author URI: http://maciejbis.net/
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/
// You can change the directory name, but please always keep slash in the end.
DEFINE('NEW_MEDIA_DIR', 'media/');
// If you want to make the uploads URLs look like:
// http://website.com/sample-media-library-image.png
// use this instead:
// DEFINE('NEW_MEDIA_DIR', '');
function bis_findfile($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, bis_findfile($dir.'/'.basename($pattern), $flags));
}
return $files;
}
function bis_get_allowed_extensions() {
return array('jpg', 'jpeg', 'jpe', 'gif', 'psng', 'bmp', 'tif', 'tiff', 'ico', 'pdf');
}
function bis_detect_image($request) {
global $wp, $wpdb;
// Allowed MIME types
$mime_types_array = bis_get_allowed_extensions();
$mime_types = implode("|", $mime_types_array);
// Prepare the new directory name for REGEX rule
$new_media_dir = preg_quote(NEW_MEDIA_DIR, '/');
// Check if requested file is an attachment
preg_match("/{$new_media_dir}(.+)\.({$mime_types})/", $wp->request, $is_file);
if(!empty($is_file)) {
// Get the uploads dir used by WordPress to host the media files
$upload_dir = wp_upload_dir();
// Decode the URI-encoded characters
$filename = basename(urldecode($wp->request));
// Check if filename contains non-ASCII characters. If does, use SQL to find the file on the server
if(preg_match('/[^\x20-\x7f]/', $filename)) {
// Check if the file is a thumbnail
preg_match("/(.*)(-[\d]+x[\d]+)([\S]{3,4})/", $filename, $is_thumb);
// Prepare the pattern
$pattern = "{$upload_dir['baseurl']}/%/{$filename}";
// Use the full size URL in SQL query (remove the thumb appendix)
$pattern = (!empty($is_thumb[2])) ? preg_replace("/(-[\d]*x[\d]*)/", "", "{$upload_dir['baseurl']}/%/{$filename}") : $pattern;
$file_url = $wpdb->get_var($wpdb->prepare("SELECT guid FROM $wpdb->posts WHERE guid LIKE %s", $pattern));
if(!empty($file_url)) {
// Replace the URL with DIR
$file_dir = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $file_url);
// Get the original path
$file_dir = (!empty($is_thumb[2])) ? str_replace($is_thumb[1], "{$is_thumb[1]}{$is_thumb[2]}", $file_dir) : $file_dir;
}
} else {
// Prepare the pattern
$pattern = "{$upload_dir['basedir']}/*/{$filename}";
$found_files = bis_findfile($pattern);
// Get the original path if file is found
$file_dir = (!empty($found_files[0])) ? $found_files[0] : false;
}
}
// Double check if the file exists
// Double check if the file exists
if(!empty($file_dir) && file_exists($file_dir)) {
$file_mime = mime_content_type($file_dir);
$file_last_modified = filemtime($current_file_name);
$file_last_modified_gmdate = gmdate('D, d M Y H:i:s', $file_last_modified);
// Set headers
header("Content-type: " . $file_mime . "\n");
header("Last-Modified: " . $file_last_modified_gmdate . " GMT\n");
readfile($file_dir);
die();
}
return $request;
}
add_filter('request', 'bis_detect_image', 999);
function bis_shorten_media_url($attachment_url) {
$mime_types_array = bis_get_allowed_extensions();
$extension = pathinfo($attachment_url, PATHINFO_EXTENSION);
// Only the selected file extension should be rewritten
if(in_array($extension, $mime_types_array)) {
$home_url = preg_quote(rtrim(get_home_url(), "/"), "/");
$attachment_url = preg_replace("/(?!{$home_url})(wp-content\/uploads\/[\d]{4}\/[\d]{2}\/)/ui", NEW_MEDIA_DIR, $attachment_url);
}
return $attachment_url;
}
add_filter('wp_get_attachment_url', 'bis_shorten_media_url');
add_filter('the_content', 'bis_shorten_media_url');
@buzi
Copy link

buzi commented Aug 20, 2020

Hi, thanks for this great, it helped me with my project. but when i apply it to images, im getting a
"The following resources are missing a cache validator. Resources that do not specify a cache validator cannot be refreshed efficiently. Specify a Last-Modified or ETag header to enable cache validation for the following resources:"
from website performance scanners.
im using a cache plugin and other images are not getting this error.
can this be solved in the code by adding "Set headers"?

@maciejbis
Copy link
Author

Hi, thanks for this great, it helped me with my project. but when i apply it to images, im getting a
"The following resources are missing a cache validator. Resources that do not specify a cache validator cannot be refreshed efficiently. Specify a Last-Modified or ETag header to enable cache validation for the following resources:"
from website performance scanners.
im using a cache plugin and other images are not getting this error.
can this be solved in the code by adding "Set headers"?

Hi @buzi,
I have just updated the snippet, could you try the new version?

@buzi
Copy link

buzi commented Aug 20, 2020

hi @maciejbis thanks for your generous support.
i will check this and let you know if any issue.
i would consider adding an etag header as well

@Blad3K1ll3r
Copy link

Blad3K1ll3r commented Aug 20, 2020

hi @maciejbis
I just downloaded this and using it as a plug-in but it won't activate and keeps giving me the following error below. I have tried to figure it out but I am very new with PHP and can't figure it out.
Parse error: syntax error, unexpected 'readfile' (T_STRING), expecting ')' in /wp-content/plugins/rewrite-wordpress-uploads-urls/rewrite-wordpress-uploads-urls.php on line 93

@maciejbis
Copy link
Author

Hi @Blad3K1ll3r,

I forgot about the semicolon - could you try to copy the code again?

@Blad3K1ll3r
Copy link

hi @maciejbis
Thank you all working now I can't believe I missed that lol

@mbaxter91288
Copy link

Hi, thanks for the snippet, helped a lot. When I implemented I got a blank screen and the image wouldn't load...a bit of digging around and I needed to change the following:

header("Last modified: " . $file_last_modified_gmdate . " GMT\n");

to:

header("Last-Modified: " . $file_last_modified_gmdate . " GMT\n");

Note the change in spelling for Last-Modified. If I am honest, I have no idea why, but it works now so thought I would mention in case it helps anyone else.

Thanks again @maciejbis for the gist!

@maciejbis
Copy link
Author

Hi, thanks for the snippet, helped a lot. When I implemented I got a blank screen and the image wouldn't load...a bit of digging around and I needed to change the following:

header("Last modified: " . $file_last_modified_gmdate . " GMT\n");

to:

header("Last-Modified: " . $file_last_modified_gmdate . " GMT\n");

Note the change in spelling for Last-Modified. If I am honest, I have no idea why, but it works now so thought I would mention in case it helps anyone else.

Thanks again @maciejbis for the gist!

Hi @mbaxter91288,

Thank you, I corrected it :) I guess that that part of code was malformed somehow when I copied and pasted it here.

Best regards,
Maciej

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment