This is an expansion upon KenB's answer; I've just included minor edits.
The Difference
Let's consider the file stackexchange.png
being uploaded to the media library.
KenB's original solution
Result: http://example.com/stackexchange-image-png/
This taps into the database for posts and pulls from the post_mime_type
column, which in this case results in image/png
.
+ These edits
Result: http://example.com/stackexchange-png/
Instead of pulling from post_mime_type
, we can pull from guid
(which in this case, results in http://example.com/wp-content/uploads/stackexchange.png
), then we can strip off everything but the file extension and work with that.
Code
So now that I've explained the difference between that solution and this one, here's how to do it. I've included and done a little editing to DisgruntledGoat and redanimalwar's answer to a question on StackOverflow.
Everything I disabled in KenB's solution, I left in the code, but just commented it out, so you can see what I actually did.
/**
* This finds the last '.' in a URI and returns the string after that.
* For example, in the case of 'example.com/photo.jpg', 'jpg' is returned.
*
* @author DisgruntledGoat
* @author redanimalwar
*
* @link https://stackoverflow.com/a/1361752/5675729
*/
function get_file_extension($uri) {
$position = strrpos($uri, '.');
$extension = $position === false ? $uri : substr($uri, $position + 1);
return $extension;
}
/**
* Filter attachment post data before it is added to the database
* - Add mime type to post_name to reduce slug collisions
*
* @author KenB
*
* @link https://wordpress.stackexchange.com/a/238205/88601 Original solution
* @link https://wordpress.stackexchange.com/a/238291/88601 This variation
*
* @param array $data Array of santized attachment post data
* @param array $postarr Array of unsanitized attachment post data
*
* @return $data, array of post data
*/
function filter_attachment_slug($data, $postarr) {
/**
* Only work on attachment types
*/
if ( ! array_key_exists( 'post_type', $data ) || 'attachment' != $data['post_type'] )
return $data;
/**
* Add mime type to the post title to build post-name
*/
$post_title = array_key_exists( 'post_title', $data ) ? $data['post_title'] : $postarr['post_title'];
/**
* This was in KenB's original solution, but was removed by Leon Williams,
* as this version does not deal with the MIME type.
*/
//$post_mime_type = array_key_exists( 'post_mime_type', $data ) ? $data['post_mime_type'] : $postarr['post_mime_type'];
/**
* This this takes the MIME type, for example, 'image/jpg', into 'image-jpg'.
* This was in KenB's original solution, but was removed by Leon Williams,
* as this version does not deal with the MIME type.
*/
//$post_mime_type = str_replace( '/', '-', $post_mime_type );
/**
* Access the 'guid' column from the database (which retrieves the link to the file),
* then send it to get_file_extension().
*
* @author Leon Williams
*/
$post_file_extention = get_file_extension($postarr['guid']);
// Instead of tacking on the MIME type, tack on the file extension that we just obtained.
$post_name = sanitize_title( $post_title . '-' /*. $post_mime_type*/ . $post_file_extention);
/**
* Generate unique slug for post name
*/
$post_ID = array_key_exists( 'ID', $data ) ? $data['ID'] : $postarr['ID'];
$post_status = array_key_exists( 'post_status', $data ) ? $data['post_status'] : $postarr['post_status'];
$post_type = array_key_exists( 'post_type', $data ) ? $data['post_type'] : $postarr['post_type'];
$post_parent = array_key_exists( 'post_parent', $data ) ? $data['post_parent'] : $postarr['post_parent'];
$post_name = wp_unique_post_slug( $post_name, $post_ID, $post_status, $post_type, $post_parent );
$data['post_name'] = $post_name;
return $data;
}
/**
* Adjust slug for uploaded files to include file extension
*/
add_filter( 'wp_insert_attachment_data', 'filter_attachment_slug', 10, 2 );
Alternative (using post_mime_type
instead of guid
)
You could also just take the png
off of image/png
(by having get_file_extension()
look for /
instead of .
), which works just as well. It's just, with this (the way I have it), you can also use the get_file_extension()
for other links as well.
Word of Caution
With a little bit of testing, I discovered that in both the original solution and this version, this filter also fires anytime you push the "Update" button while editing an attachment.
For example, let's say you're editing an attachment by the name of example.png
and it has the custom slug of example-file-slug
(let's suppose you gave it that custom slug a long time ago). Today you're editing the description and when you're finished with the description and hit "Update", this filter will fire and will automatically change the slug from example-file-slug
to example-png
in addition to updating the description. If you try to go back and change the slug to anything else, again, the filter will fire when you hit "Update" and will override your attempt to change the slug.
This poses no problem for me personally, but it may be something to consider for others.
Workarounds
If you want to change the slug name, you would have to disable this filter (say, by commenting it out) then save your changes to the attachment, then enable the filter again. Alternatively, you could edit the database directly.
I'm sure there's a way to code a solution, but I don't currently have one.
Thanks to these fine people: