
Add the code below to your theme’s functions.php or use Code Snippet Plugins. Then Go to Tools > Duplicate Media in your WordPress admin, Click “Find Duplicates” to see what would be affected. Backup your Site and Media first, then click “Remove Duplicates”
<?php
// Hide duplicate media files - keep only the first one (lowest ID)
function hide_duplicate_media_files($query) {
global $pagenow, $wpdb;
// Only apply on media library page
if (!is_admin() || $pagenow !== 'upload.php') {
return;
}
// Only for attachment queries
if (!$query->is_main_query() || $query->get('post_type') !== 'attachment') {
return;
}
// Get duplicate IDs to hide (keep the one with lowest ID for each filename)
$duplicates_to_hide = $wpdb->get_col("
SELECT p1.ID
FROM {$wpdb->posts} p1
INNER JOIN (
SELECT post_title, MIN(ID) as keep_id
FROM {$wpdb->posts}
WHERE post_type = 'attachment'
GROUP BY post_title
HAVING COUNT(*) > 1
) p2 ON p1.post_title = p2.post_title
WHERE p1.post_type = 'attachment'
AND p1.ID != p2.keep_id
");
if (!empty($duplicates_to_hide)) {
$existing_excluded = $query->get('post__not_in') ?: array();
$query->set('post__not_in', array_merge($existing_excluded, $duplicates_to_hide));
}
}
add_action('parse_query', 'hide_duplicate_media_files');
// Also handle AJAX requests for media modal/grid view
function hide_duplicates_in_ajax($query_args) {
global $wpdb;
if (is_admin() && defined('DOING_AJAX') && DOING_AJAX) {
// Get duplicate IDs to hide
$duplicates_to_hide = $wpdb->get_col("
SELECT p1.ID
FROM {$wpdb->posts} p1
INNER JOIN (
SELECT post_title, MIN(ID) as keep_id
FROM {$wpdb->posts}
WHERE post_type = 'attachment'
GROUP BY post_title
HAVING COUNT(*) > 1
) p2 ON p1.post_title = p2.post_title
WHERE p1.post_type = 'attachment'
AND p1.ID != p2.keep_id
");
if (!empty($duplicates_to_hide)) {
$existing_excluded = isset($query_args['post__not_in']) ? $query_args['post__not_in'] : array();
$query_args['post__not_in'] = array_merge($existing_excluded, $duplicates_to_hide);
}
}
return $query_args;
}
add_filter('ajax_query_attachments_args', 'hide_duplicates_in_ajax');
// Quick test - add this temporarily to see what duplicates exist
function show_duplicate_info() {
global $wpdb, $pagenow;
if (is_admin() && $pagenow === 'upload.php') {
$duplicates = $wpdb->get_results("
SELECT post_title, GROUP_CONCAT(ID ORDER BY ID) as all_ids, COUNT(*) as count
FROM {$wpdb->posts}
WHERE post_type = 'attachment'
GROUP BY post_title
HAVING COUNT(*) > 1
ORDER BY count DESC
LIMIT 10
");
if (!empty($duplicates)) {
echo '<div class="notice notice-info"><p><strong>Duplicate files found:</strong><br>';
foreach ($duplicates as $dup) {
echo 'File: ' . esc_html($dup->post_title) . ' - IDs: ' . $dup->all_ids . ' (' . $dup->count . ' copies)<br>';
}
echo '</p></div>';
}
}
}
add_action('admin_notices', 'show_duplicate_info');
?>
Thanks to claude ai for this
