Charlie,
Thanks for the pointer to the plugin! It has led me to a lighter-weight alternative via functions.php, which works (something for a future release?)
/**
* Lightweight Media File Replacement
* Works in both Grid and List views
*/
// Add "Replace File" link to List View
add_filter('media_row_actions', 'cww_add_replace_media_link', 10, 2);
function cww_add_replace_media_link($actions, $post) {
$actions['replace_file'] = '<a href="' . admin_url('upload.php?page=cww-replace-media&attachment_id=' . $post->ID) . '">Replace File</a>';
return $actions;
}
// Add "Replace File" button to Grid View and Edit Media modal
add_filter('attachment_fields_to_edit', 'cww_add_replace_field_to_modal', 10, 2);
function cww_add_replace_field_to_modal($form_fields, $post) {
$replace_url = admin_url('upload.php?page=cww-replace-media&attachment_id=' . $post->ID);
$form_fields['replace_file'] = array(
'label' => 'Replace File',
'input' => 'html',
'html' => '<a href="' . esc_url($replace_url) . '" class="button button-secondary">Replace This File</a>',
'helps' => 'Upload a new file to replace this one whilst keeping the same ID and URL'
);
return $form_fields;
}
// Register admin page for replacement
add_action('admin_menu', 'cww_register_replace_media_page');
function cww_register_replace_media_page() {
add_submenu_page(
null, // Hidden from menu
'Replace Media File',
'Replace Media',
'upload_files',
'cww-replace-media',
'cww_replace_media_page'
);
}
// Replacement page UI
function cww_replace_media_page() {
if (!current_user_can('upload_files')) {
wp_die('Unauthorised');
}
$attachment_id = isset($_GET['attachment_id']) ? intval($_GET['attachment_id']) : 0;
if (!$attachment_id) {
wp_die('Invalid attachment ID');
}
$attachment = get_post($attachment_id);
$file_path = get_attached_file($attachment_id);
$file_url = wp_get_attachment_url($attachment_id);
?>
<div class="wrap">
<h1>Replace Media File</h1>
<p><strong>Current file:</strong> <?php echo esc_html(basename($file_path)); ?></p>
<p><strong>URL:</strong> <code><?php echo esc_html($file_url); ?></code></p>
<form method="post" enctype="multipart/form-data">
<?php wp_nonce_field('cww_replace_media', 'cww_replace_nonce'); ?>
<input type="hidden" name="attachment_id" value="<?php echo esc_attr($attachment_id); ?>">
<p>
<label for="replacement_file"><strong>Choose replacement file:</strong></label><br>
<input type="file" name="replacement_file" id="replacement_file" required>
</p>
<p>
<label>
<input type="checkbox" name="keep_filename" value="1" checked>
Keep original filename (preserves URL and all references)
</label>
</p>
<?php submit_button('Replace File'); ?>
</form>
</div>
<?php
}
// Handle file replacement
add_action('admin_init', 'cww_handle_replace_media');
function cww_handle_replace_media() {
if (!isset($_POST['cww_replace_nonce']) || !wp_verify_nonce($_POST['cww_replace_nonce'], 'cww_replace_media')) {
return;
}
if (!current_user_can('upload_files')) {
wp_die('Unauthorised');
}
$attachment_id = intval($_POST['attachment_id']);
$keep_filename = isset($_POST['keep_filename']);
if (empty($_FILES['replacement_file']['tmp_name'])) {
wp_die('No file uploaded');
}
$old_file_path = get_attached_file($attachment_id);
// Determine new filename
if ($keep_filename) {
$new_filename = basename($old_file_path);
} else {
$new_filename = sanitize_file_name($_FILES['replacement_file']['name']);
}
$new_file_path = dirname($old_file_path) . '/' . $new_filename;
// Delete old file
if (file_exists($old_file_path)) {
@unlink($old_file_path);
}
// Move uploaded file to correct location
if (!move_uploaded_file($_FILES['replacement_file']['tmp_name'], $new_file_path)) {
wp_die('Failed to replace file');
}
// Update attachment metadata
$filetype = wp_check_filetype($new_file_path);
wp_update_post([
'ID' => $attachment_id,
'post_mime_type' => $filetype['type'],
]);
// Update attached file path
update_attached_file($attachment_id, $new_file_path);
// Regenerate metadata for images
if (wp_attachment_is_image($attachment_id)) {
wp_generate_attachment_metadata($attachment_id, $new_file_path);
}
// Clear caches
clean_post_cache($attachment_id);
wp_redirect(admin_url('upload.php?replaced=1'));
exit;
}
// Success notice
add_action('admin_notices', 'cww_replace_media_notice');
function cww_replace_media_notice() {
if (isset($_GET['replaced'])) {
echo '<div class="notice notice-success is-dismissible"><p>File replaced successfully!</p></div>';
}
}
Many thanks for such a quick response. So much appreciated!
Christopher