WordPress 使用工作缩略图重命名附件文件

Posted

技术标签:

【中文标题】WordPress 使用工作缩略图重命名附件文件【英文标题】:WordPress rename attachment file with working thumbnails 【发布时间】:2021-03-07 11:20:34 【问题描述】:

我正在尝试编写一个函数来重命名附件文件,无论是在上传时,还是在上传后。

我编写了一个很好的函数来执行此操作,但它会导致 WP 仪表板中缺少缩略图。我怀疑这是因为 GUID 出错了,但是 WP 现在无法更改该 GUID(我认为),所以我不确定还能做什么。希望这里有人可以提供帮助。

这是我所拥有的,基于我在网上可以找到的所有内容。

add_action("add_attachment", "rename_attachment", 10, 1);
function rename_attachment($post_id) 
     custom_attachment_rename($post_id, "My name filename here");


function custom_attachment_rename( $post_id, $new_filename = 'new filename' )

    // 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'], $new_filename);

    // Build out path to new file
    $new_path = $path_info['dirname']. "/" . $safe_filename . "." .$path_info['extension'];
    
    // Rename the file and update it's location in WP
    rename($og_path, $new_path);    
    update_attached_file( $post_id, $new_path );

    // URL to the new file
    $new_url = wp_get_attachment_url($post_id);
    
    // Update attachment data
    $id = wp_update_post([
        'ID' => $post_id,
        'post_title' => $new_filename,
        'guid' => $new_url // Doesn't seem to work
    ]);
    
    // Try this to reset the GUID for the attachment. Doesn't seem to actually reset it.
    // global $wpdb;
    // $result = $wpdb->update($wpdb->posts, ['guid' => $new_url], ['ID' => $post_id]);
    
    // Update all links to old "sizes" files, or create it for new upload.
    $metadata = get_post_meta($post_id, '_wp_attachment_metadata', true);
    if( empty($metadata) ) 

        // New upload.
        $data = wp_generate_attachment_metadata($post_id, $new_path);
        //update_post_meta($post_id, '_wp_attachment_metadata', $data); // Tried this. Doesn't work.
        wp_update_attachment_metadata($post_id, $data); // Also doesn't work
        
     else 
        // Regenerating an existing image
        // TODO loop through $metadata and update the filename and resave? Maybe just delete it and regenerate instead?
    
    
    // TODO Update use of the old filename in post_content throughout site

到目前为止,这些都是我看过的有用的帖子。

https://wordpress.stackexchange.com/questions/166943/how-to-rename-an-image-attachment-filename-using-php https://wordpress.stackexchange.com/questions/30313/change-attachment-filename https://wordpress.stackexchange.com/a/221254/4562

奇怪的是,如果我在这个函数的末尾die,那么它就起作用了。所以我怀疑 WP 中的其他东西正在覆盖这个附件的_wp_attachment_metadata。这就是为什么我怀疑 GUID 是问题所在。其他东西正在通过GUID 查找附件并找到一个不再存在的文件的URL(因为我更改了文件名)并在错误的文件路径上运行wp_generate_attachment_metadata。这是我的预感。

我没有安装任何其他插件。

【问题讨论】:

【参考方案1】:

您的代码不起作用的原因与 GUID 无关。

这是因为,在 WP 核心中,函数 wp_update_attachment_metadata() 在媒体上传请求处理结束时以原始文件名调用。并且钩子 add_attachment 在 wp_insert_attachment() 函数中被调用。

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;

我们可以使用“wp_update_attachment_metadata”过滤器将元数据更改为新文件名。

请检查以下代码。我测试过,效果很好。

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();

【讨论】:

这很高兴看到。虽然这会导致原始图像中间尺寸仍然在服务器上吗?我可能需要扩展它以重命名这些文件,然后在 post_content 中搜索并替换这些文件的使用。 结果将与上传先前重命名的图像文件完全相同。所有图像大小,包括插件注册的工作。而且,是的,您需要根据需要扩展该功能。 在第 4998 行的 /www/wp-includes/formatting.php 中获取“致命错误:允许的内存大小为 268435456 字节已用尽(尝试分配 262144 字节)致命错误:允许的内存大小为 268435456 字节用这个在第 0 行的 Unknown 中耗尽(试图分配 262144 字节)。【参考方案2】:

我把@chengmin 的回答变成了这样的一个函数:

/**
* Renames a file. Will also regenerate all the thumbnails that go with the file.
* @SEE https://***.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;

【讨论】:

以上是关于WordPress 使用工作缩略图重命名附件文件的主要内容,如果未能解决你的问题,请参考以下文章

WordPress 实现附件上传自动重命名但不改变附件标题

Wordpress 媒体缩略图/固定链接

wordpress上传图片时重命名--修改插件时遇到的一些问题

php 创建 zip 文件(来自 post 附件 wordpress)

DIScord.js 将附件放入嵌入的缩略图中不显示

修改WordPress中上传附件2M大小限制的方法/php+iis上传附件默认大小修改方法