WordPress rename attachment file with working thumbnails
The reason your code doesn't work is not related to the GUID.
It is because, in WP core, the function wp_update_attachment_metadata() is called with the original file name at the end of the media upload request handling. And the hook add_attachment is called inside wp_insert_attachment() function.
function media_handle_upload( $file_id, $post_id, $post_data = array(), $overrides = array( 'test_form' => false ) ) { ... ... // Save the data. $attachment_id = wp_insert_attachment( $attachment, $file, $post_id, true ); if ( ! is_wp_error( $attachment_id ) ) { // Set a custom header with the attachment_id. // Used by the browser/client to resume creating image sub-sizes after a PHP fatal error. if ( ! headers_sent() ) { header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id ); } // The image sub-sizes are created during wp_generate_attachment_metadata(). // This is generally slow and may cause timeouts or out of memory errors. wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) ); } return $attachment_id;}
We can use the "wp_update_attachment_metadata" filter to change the metadata with the new file name.
Please check the below code. I tested and it is working well.
class CustomAttachmentRename { public $new_filename = 'custom file'; private $new_path; function __construct () { add_action("add_attachment", array($this, "rename_attachment"), 10, 1); } function rename_attachment($post_id) { // Get path info of orginal file $og_path = get_attached_file($post_id); $path_info = pathinfo($og_path); // Santize filename $safe_filename = wp_unique_filename($path_info['dirname'], $this->new_filename); // Build out path to new file $this->new_path = $path_info['dirname']. "/" . $safe_filename . "." .$path_info['extension']; // Rename the file and update it's location in WP rename($og_path, $this->new_path); update_attached_file( $post_id, $this->new_path ); // Register filter to update metadata. add_filter('wp_update_attachment_metadata', array($this, 'custom_update_attachment_metadata'), 10, 2); } function custom_update_attachment_metadata($data, $post_id) { return wp_generate_attachment_metadata($post_id, $this->new_path); }}$customAttachmentRename = new CustomAttachmentRename();$customAttachmentRename->new_filename = "test image" . time();
I turned @chengmin answer into a single function like this:
/*** Renames a file. Will also regenerate all the thumbnails that go with the file.* @SEE https://stackoverflow.com/questions/64990515/wordpress-rename-attachment-file-with-working-thumbnails** @param string $post_id The WordPress post_id for the attachment* @param string $new_file_name The filename (without extension) that you want to rename to*/ function attachment_rename($post_id, $filename) { // Get path info of orginal file $og_url = wp_get_attachment_url($post_id); $og_path = get_attached_file($post_id); $path_info = pathinfo($og_path); $og_meta = get_post_meta($post_id, '_wp_attachment_metadata', true); // Santize filename $safe_filename = wp_unique_filename($path_info['dirname'], $filename); // Build out path to new file $new_path = $path_info['dirname']. "/" . $safe_filename . "." .$path_info['extension']; // Rename the file in the file system rename($og_path, $new_path); // Delete old image sizes if we have them if( !empty($og_meta) ) { delete_attachment_files($post_id); } // Now save new path to file in WP update_attached_file( $post_id, $new_path ); // Register filter to update metadata $new_data = wp_generate_attachment_metadata($post_id, $new_path); return add_filter('wp_update_attachment_metadata', function($data, $post_id) use ($new_data) { return $new_data; }, 10, 2);}/** * Delete all old image files, if they aren't used post_content anywhere. * The dont-delete check isn't perfect, it will give a lot of false positives (keeping more files than it should), but it's best I could come up with. * @SEE https://github.com/WordPress/WordPress/blob/f4cda1b62ffca52115e4b04d9d75047060d69e68/wp-includes/post.php#L5983 * * @param string $post_id The WordPress post_id for the attachment */ function delete_attachment_files($post_id) { $meta = wp_get_attachment_metadata( $post_id ); $backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true ); $file = get_attached_file( $post_id ); $url = wp_get_attachment_url($post_id); // Remove og image so it doesn't get deleted in wp_delete_attachment_files() $meta['original_image'] = ""; // Check if image is used in a post somehwere $url_without_extension = substr($url, 0 , (strrpos($url, "."))); $args = [ "s" => $url_without_extension, "posts_per_page" => 1, "post_type" => "any" ]; $found = get_posts($args); if( empty($found) ) { return wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ); } return false;}