You upload Health & Safety Authority.JPG and wonder whether you need a snippet to fix the name. Most “rename uploads” snippets repeat work WordPress already does, and the ones that rebuild names from scratch can make some of them worse.
&, % and brackets, strips accents and lowercases the extension. What it leaves alone is capital letters, a few characters such as the en dash, and non-Latin names. If you want lowercase names, a six-line filter on sanitize_file_name does it. A bigger snippet that rebuilds the name from scratch is where things go wrong.Table of Contents
What WordPress does to upload filenames
Every upload passes through sanitize_file_name() before it’s written to disk. Eleven test files uploaded to a clean WordPress 7.0.2 test site show what that means in practice. Here is what core did on its own with eight of them:
| Uploaded as | WordPress stored |
|---|---|
Health & Safety Authority.JPG | Health-Safety-Authority.jpg |
IMG_2901 (1).png | IMG_2901-1.png |
Résumé Final v2.PNG | Resume-Final-v2.png |
my photo--final__.jpeg | my-photo-final__.jpeg |
100% done!.png | 100-done.png |
file.name.with.dots.jpg | file.name_.with_.dots_.jpg |
Café menu – summer.jpg | Cafe-menu-–-summer.jpg |
製品写真.png | 製品写真.png |
That covers most of what a rename snippet promises. Spaces and runs of hyphens collapse, the risky characters go (slashes, quotes, &, %, #, brackets), accented letters become plain ones, and .JPG becomes .jpg.
The odd-looking file.name_.with_.dots_.jpg is deliberate. WordPress puts an underscore after each extra dot so a name like photo.php.jpg can’t be treated as a script by a server that reads every extension. It can still catch you out: if a script or sync tool uploads x.cover.webp and later looks the file up by its exact name, it won’t find it, because WordPress stored x.cover_.webp. Use hyphens inside names (x-cover.webp) and the problem disappears.
WordPress already does most of what a rename snippet promises.
What core leaves alone, and whether it matters
Three things survive, and only one of them can cause a real problem.
Capital letters. Health-Safety-Authority.jpg keeps its capitals. File addresses are case-sensitive on most web servers, so a link typed as health-safety-authority.jpg returns a 404. That’s the one good reason to lowercase.
The en dash and non-Latin names. – and 製品写真 stay as they are, and in the address they become percent-encoded strings like %E2%80%93. Browsers handle that fine. It’s untidy when someone copies the link, and that’s all.
Underscores. IMG_2901 keeps its underscore. Google’s URL guidance prefers hyphens between words, but an underscore in a filename doesn’t break anything.
How often does each trait turn up? One real site’s media library, checked on 10 October 2026, held 394 files. Fourteen had a capital letter, 22 an underscore, one an extra dot. None had a non-Latin name, and none had a camera name like IMG_1234, because every image there was named before upload. Run the same count on your own library before deciding a snippet is worth adding.
Why a rebuild-from-scratch snippet backfires
A common style of “force clean filenames” snippet, often written for WordPress networks, rebuilds every name from scratch: lowercase, ASCII letters, digits and hyphens only, and a site-number prefix such as s2- on a multisite network. Testing one such snippet on a test site showed how it goes wrong:
| Uploaded as | WordPress alone | With the rebuild snippet |
|---|---|---|
Health & Safety Authority.JPG | Health-Safety-Authority.jpg | health-safety-authority-jpg.jpg |
Résumé Final v2.PNG | Resume-Final-v2.png | resume-final-v2-png.png |
製品写真.png | 製品写真.png | file.png |
s3-bucket-diagram.png (on site 2) | s3-bucket-diagram.png | s2-bucket-diagram.png |
Every upper-case extension doubled. The snippet lowercased the extension first and then asked PHP to cut that lowercase extension off the original name. .JPG isn’t .jpg, so nothing was cut, and the old extension became part of the name. Many cameras save photos with an upper-case .JPG, so this would have hit a lot of real uploads.
Non-Latin names vanished. Anything that wasn’t a Latin letter or digit was deleted, so a Japanese filename became file.png, and the next one would be file-1.png. WordPress on its own kept the original name.
The site prefix ate real words. To avoid stamping a file twice, the snippet removed any existing s + digits + hyphen from the start of a name. A diagram called s3-bucket-diagram.png lost its s3. The prefix was redundant anyway: a multisite network already stores each subsite’s uploads in their own folder (uploads/sites/2/ and so on).
Snippets like this are often sold on the claim that lowercase hyphenated names make the server faster and block directory-traversal attacks. Nothing backs either claim. A file’s name doesn’t change how fast the server finds it, and core already removes the slashes those attacks need.
The snippet’s worst bug hit the most common upload there is: a photo ending in .JPG.
The six lines that help
If you want lowercase names, add to what WordPress already did rather than replacing it. The sanitize_file_name filter receives the name after core has cleaned it:
// Runs after WordPress's own cleaning: lowercase the name and turn en/em dashes into hyphens.
add_filter( 'sanitize_file_name', function ( $filename ) {
$filename = str_replace( array( "\u{2013}", "\u{2014}" ), '-', $filename );
$filename = preg_replace( '/-{2,}/', '-', $filename );
return strtolower( $filename );
} );
Code language: PHP (php)
On the test site, Health & Safety Authority.JPG became health-safety-authority.jpg, Café menu – summer.jpg became cafe-menu-summer.jpg, and the Japanese name and s3-bucket-diagram.png came through untouched. Add it as a code snippet or a small must-use plugin; it’s the kind of job a snippet handles better than a plugin.
It only affects new uploads. Renaming files already in your library changes their addresses, and every post that embeds them would need its links rewritten, the same search-and-replace job as a domain move. For a dozen or so files with capitals, that’s rarely worth it.
What no snippet can fix
A filter can tidy characters. It can’t turn IMG_2901.jpg into blue-ceramic-teapot.jpg, and that’s the part search engines can use: Google says a filename gives it light clues about what an image shows. Naming files for what they show happens before upload, by a person or by whatever tool prepares your images. If you keep a managed image library, naming files once in the library solves this for every upload that follows.
The short version
WordPress already strips spaces, symbols and accents from upload filenames and lowercases the extension. It keeps capitals, en dashes and non-Latin names. Capitals are the only one that can break a link. A six-line filter that lowercases what core produced fixes that; a snippet that rebuilds names from scratch can double extensions, erase non-Latin names and eat real words. Descriptive names still come from you.
Frequently Asked Questions
Why did WordPress add an underscore to my filename?
Your file had more than one dot in its name. WordPress adds an underscore after each extra dot (file.name_.jpg) so a name like photo.php.jpg can’t be run as a script on a server that reads every extension. Use hyphens instead of dots inside names and it won’t happen.
Will a filename snippet rename images I’ve already uploaded?
No. The filter runs when a file is uploaded, so existing files keep their names and addresses. Renaming them means moving the files and rewriting every link to them, so only do it if broken links are actually a problem.