Як безпечно видалити неприкріплені зображення з медіатеки WordPress
Привіт:) З часом у медіатеці WordPress накопичуються сотні або навіть тисячі зображень, частина з яких більше не використовується. Це можуть бути старі картинки, завантажені під час редагування записів, або неприкріплені зображення — файли, що колись були додані, але тепер не прив’язані до жодної сторінки чи публікації.
На перший погляд, це не проблема. Але насправді надлишок таких файлів створює серйозне навантаження на сервер, займає місце в резервних копіях і уповільнює роботу сайту. Кожен непотрібний файл — це додаткові мегабайти, які зберігаються і обробляються щоразу, коли ви робите бекап, оновлюєте сайт чи переносите його на інший хостинг.
Регулярне видалення неприкріплених зображень у WordPress допомагає підтримувати порядок у медіатеці, зменшити розмір бази даних і прискорити завантаження сайту. У цій статті розгляну, як безпечно знайти та видалити такі файли — як за допомогою плагінів, так і власним кодом.
Видалення неприкріплених зображень за допомогою плагіну
- Встановіть та активуйте плагін Media Cleaner (https://wordpress.org/plugins/media-cleaner/).
- Перейдіть в адмін-меню Медіафайли -> Cleaner та клацніть кнопку Scan.
- Виділіть знайдені зображення та натисніть Delete All.

Видалення неприкріплених зображень через власний код
Додайте наступний код у файл functions.php.
/**
* Automatically Remove Unused Images from the WordPress Media Library
*
* Mykhailo Petrov
* https://petrov.net.ua/
*
* v.1.0
*
*/
if ( ! function_exists( 'mp_get_used_image_urls_and_ids' ) ) {
// Збирає всі використані URL і ID зображень
function mp_get_used_image_urls_and_ids() {
global $wpdb;
$results = $wpdb->get_col( "
SELECT post_content FROM {$wpdb->posts}
WHERE post_status IN ('publish', 'draft', 'pending', 'future')
AND post_type IN ('post', 'page')
" );
$used_urls = array();
$used_ids = array();
if ( empty( $results ) ) {
return array(
'urls' => array(),
'ids' => array()
);
}
foreach ( $results as $content ) {
if ( $content === null ) continue;
$content = ( string ) $content;
// <img src="...">
if ( preg_match_all( '/<img[^>]+src=[\'"]([^\'"]+)[\'"]/', $content, $m ) && ! empty( $m[1] ) ) {
$used_urls = array_merge( $used_urls, $m[1] );
}
// srcset="url1 1x, url2 2x"
if ( preg_match_all( '/<img[^>]+srcset=[\'"]([^\'"]+)[\'"]/', $content, $m2 ) && ! empty( $m2[1] ) ) {
foreach ( $m2[1] as $srcset ) {
$parts = explode( ',', $srcset );
foreach ( $parts as $part ) {
$url = trim( preg_replace( '/\s+\d+(w|x)$/', '', $part ) );
if ( $url ) $used_urls[] = $url;
}
}
}
// wp-image-123
if ( preg_match_all( '/wp-image-([0-9]+)/', $content, $idm ) && ! empty( $idm[1] ) ) {
foreach ( $idm[1] as $id ) {
$id = ( int ) $id;
if ( $id ) {
$used_ids[] = $id;
$u = wp_get_attachment_url( $id );
if ( $u ) $used_urls[] = $u;
}
}
}
// [gallery ids="1,2,3"]
if ( preg_match_all( '/\[gallery[^\]]*ids=[\'"]?([0-9,\s]+)[\'"]?/', $content, $gm ) && ! empty( $gm[1] ) ) {
foreach ( $gm[1] as $ids ) {
foreach ( explode( ',', $ids ) as $id ) {
$id = ( int ) trim( $id );
if ( $id ) {
$used_ids[] = $id;
$u = wp_get_attachment_url( $id );
if ( $u ) $used_urls[] = $u;
}
}
}
}
}
// Featured images
$post_ids = $wpdb->get_col( "
SELECT ID FROM {$wpdb->posts}
WHERE post_status IN ('publish', 'draft', 'pending', 'future')
AND post_type IN ('post', 'page')
" );
if ( ! empty( $post_ids ) ) {
foreach ( $post_ids as $pid ) {
$thumb_id = get_post_thumbnail_id( $pid );
if ( $thumb_id ) {
$used_ids[] = ( int ) $thumb_id;
$u = wp_get_attachment_url( $thumb_id );
if ( $u ) $used_urls[] = $u;
}
}
}
$used_urls = array_unique( array_filter( $used_urls ) );
$used_ids = array_unique( array_filter( $used_ids ) );
return array(
'urls' => $used_urls,
'ids' => $used_ids
);
}
}
if ( ! function_exists( 'mp_find_unused_images' ) ) {
// Знаходить невикористані зображення
function mp_find_unused_images() {
global $wpdb;
$used = mp_get_used_image_urls_and_ids();
$used_urls = $used['urls'];
$used_ids = $used['ids'];
$unused = array();
$attachments = get_posts(
array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'numberposts' => -1,
'post_status' => 'inherit',
)
);
foreach ( $attachments as $attachment ) {
$att_id = ( int ) $attachment->ID;
$att_url = wp_get_attachment_url( $att_id );
if ( ! $att_url ) continue;
// Якщо ID вже використовується
if ( in_array( $att_id, $used_ids, true ) ) continue;
$found = false;
// Прямий збіг URL
foreach ( $used_urls as $u ) {
if ( strpos( $u, $att_url ) !== false ) {
$found = true;
break;
}
}
if ( $found ) continue;
// Перевірка за базовим іменем (photo-150x150.jpg ~ photo.jpg)
$att_basename = pathinfo( $att_url, PATHINFO_FILENAME );
foreach ( $used_urls as $u ) {
if ( strpos( $u, $att_basename ) !== false ) {
$found = true;
break;
}
}
if ( $found ) continue;
// Перевірка у postmeta (ID або URL)
$meta_like = '%' . $wpdb->esc_like( ( string )$att_id ) . '%';
$meta_exists = $wpdb->get_var( $wpdb->prepare(
"SELECT meta_id FROM {$wpdb->postmeta} WHERE meta_value LIKE %s LIMIT 1",
$meta_like
) );
if ( $meta_exists ) continue;
// Якщо нічого не знайдено — вважаємо невикористаним
$unused[] = $attachment;
}
return $unused;
}
}
if ( ! function_exists( 'mp_cleanup_unused_images_admin_page' ) ) {
// Сторінка в адмінці
function mp_cleanup_unused_images_admin_page() {
if ( ! current_user_can( 'manage_options' ) ) return;
echo '<div class="wrap"><h1>Unused Images</h1>';
$unused = mp_find_unused_images();
// Видалення
if ( isset( $_POST['delete_unused'] ) && check_admin_referer( 'delete_unused_images' ) ) {
$deleted = 0;
foreach ( $unused as $image ) {
if ( wp_delete_attachment( $image->ID, true ) ) {
$deleted++;
}
}
echo '<div class="updated notice"><p>Deleted ' . esc_html( $deleted ) . ' unused images.</p></div>';
$unused = mp_find_unused_images(); // оновити список
}
if ( empty( $unused ) ) {
echo '<p><strong>No unused images found.</strong></p>';
} else {
echo '<p><strong>' . count( $unused ) . ' unused images found.</strong></p>';
echo '<form method="post">';
wp_nonce_field( 'delete_unused_images' );
echo '<input type="submit" name="delete_unused" value="Delete All Unused Images" class="button button-primary" style="background:#d63638;border-color:#d63638;">';
echo '</form>';
echo '<ul style="margin-top:20px;">';
foreach ( $unused as $img ) {
$url = esc_url( wp_get_attachment_url( $img->ID ) );
$thumb = wp_get_attachment_image( $img->ID, array( 60, 60 ), false, array( 'style' => 'vertical-align:middle;margin-right:10px;' ) );
echo '<li>' . $thumb . esc_html( $img->post_title ) . ' – <code>' . $url . '</code></li>';
}
echo '</ul>';
}
echo '</div>';
}
}
if ( ! function_exists( 'mp_register_unused_images_menu' ) ) {
add_action( 'admin_menu', 'mp_register_unused_images_menu' );
// Реєстрація сторінки в меню
function mp_register_unused_images_menu() {
add_management_page(
'Unused Images Cleanup',
'Unused Images',
'manage_options',
'unused-images',
'mp_cleanup_unused_images_admin_page'
);
}
}
Далі відкрийте адмін-меню Інструменти -> Unused Images. Якщо були знайдені неприкріплені зображення, натисніть кнопку Delete All Unused Images.

