Aynı Sluga Sahip Görselleri Toplu Öne Çıkar
Sitede webmaster için bazen görseller sessizce kenarda kalır, yazılar ise eksik gibi görünür. Tam da burada devreye girer küçük ama etkili bir yöntem. Aynı slug yapısına sahip görselleri topluca öne çıkan görsel yapmak. İlk bakışta karmaşık gibi durur, ama aslında oldukça pratik bir mantığı vardır. Düşünün, yüzlerce yazınız var ve her biri için tek tek görsel seçmek gerekiyor.
“Yazı slug ile resim slug birebir aynı ise bu kod işinizi görecek resimleri görerek öne çıkan görsel olarak resimleri tek seferde resmi atayabileceksiniz.” Bu meta _thumbnail_id ile yapılır.
Temelde yapılan işlem basit aslında, ama etkisi büyük olur. Yazının URL yapısı ile görsel dosya adı birbirine yakınsa, sistem bunu fark eder. Yani istanbul-gezi-rehberi adlı bir yazı varsa ve aynı isimde bir görsel yüklediyseniz, eşleşme kendiliğinden oluşur. Elle uğraşmadan, tek tek seçmeden, otomatik şekilde ilerler süreç. Bir nevi taşları yerine oturtmak gibi düşünün, doğru parçalar bir araya gelir.
Bu yöntemi kullanırken dikkat edilmesi gereken küçük detaylar da yok değil. Görsellerin gelişigüzel isimlendirilmesi işleri zorlaştırır. Halbuki düzenli bir yapı kurulduğunda her şey rayına girer. Biraz disiplin, biraz planlama, sonrası kendiliğinden akar. Hele ki içerik sayısı arttıkça bu düzenin değeri daha net anlaşılır.
Toplu işlem tarafına geldiğimizde ise asıl rahatlık hissedilir. Tek tek uğraşmak yerine, bir liste üzerinden ilerlemek mümkün olur. Eşleşen içerikler sıralanır, siz de sadece onay verirsiniz. Sanki uzun bir işi kısa yoldan halletmiş gibi hissedersiniz. Zaman kazancı bir yana, hata payı da ciddi şekilde azalır.
Bir de işin görünmeyen tarafı var, hani ziyaretçi deneyimi dediğimiz mesele. Görselsiz bir yazı çoğu zaman eksik kalır. Okuyucu sayfaya girer, ama bir şeyler oturmaz yerine. Oysa doğru görsel, yazının ruhunu tamamlar. İşte bu yöntemle o boşluklar sessizce kapanır.
Sonuçta bakıldığında, slug aynı görselleri toplu öne çıkan yapmak bir lüks değil, ihtiyaç haline gelir. Özellikle büyüyen sitelerde bu tür pratik çözümler fark yaratır. Baştan düzen kurulduğunda işler çorap söküğü gibi ilerler, uğraştırmaz insanı. Siz de içeriklerinizi daha düzenli, daha bütünlüklü görmek istiyorsanız bu yöntemi denemekte geç kalmayın. Küçük bir dokunuş gibi görünür, ama etkisi sandığınızdan daha iyidir.
Functions.php ile Görsel Eşleştirme Kodu Nasıl Eklenir?
add_action('admin_menu', function() {
add_menu_page(
'Görsel Eşleştirici',
'Görsel Eşleştir',
'manage_options',
'image-matcher',
'render_image_matcher_page',
'dashicons-images-alt2'
);
});
/**
* Admin Sayfası Görünümü
*/
function render_image_matcher_page() {
global $wpdb;
// Güvenlik anahtarı (Nonce) oluştur
$nonce = wp_create_nonce("assign_nonce");
?>
<div class="wrap">
<h1>Görsel Eşleştirme Paneli</h1>
<div class="notice notice-info">
<p>Sistem, yazıların <b>slug</b> (kısa isim) değerini dosya adında barındıran görselleri bulur.</p>
</div>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th style="width: 100px;">Görsel</th>
<th>Yazı Başlığı</th>
<th>Eşleşen Dosya Yolu</th>
<th style="width: 200px;">İşlem</th>
</tr>
</thead>
<tbody id="match-list">
<?php
// Tüm yayınlanmış yazıları çek
$posts = get_posts([
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'publish'
]);
$found_count = 0;
foreach ($posts as $post) {
$slug = $post->post_name;
// SQL sorgusu - Prepare fonksiyonu düzeltildi
// esc_like() ile slug içindeki özel karakterler temizlendi
$attachment = $wpdb->get_row($wpdb->prepare(
"SELECT post_id, meta_value FROM {$wpdb->postmeta}
WHERE meta_key = '_wp_attached_file'
AND meta_value LIKE %s
LIMIT 1",
'%' . $wpdb->esc_like($slug) . '%'
));
if ($attachment) {
$found_count++;
$image_id = $attachment->post_id;
$file_path = $attachment->meta_value;
$image_url = wp_get_attachment_thumb_url($image_id);
$has_thumb = has_post_thumbnail($post->ID) ? '<br><small style="color:#27ae60; font-weight:bold;">(Zaten Bir Görseli Var)</small>' : '';
echo "<tr id='post-row-{$post->ID}'>";
echo "<td><img src='{$image_url}' width='80' height='80' style='object-fit:cover; border:1px solid #ccc; border-radius:4px;'></td>";
echo "<td><strong>" . esc_html($post->post_title) . "</strong>{$has_thumb}</td>";
echo "<td><code>" . esc_html($file_path) . "</code></td>";
echo "<td>
<button class='button button-primary do-assign'
data-post-id='{$post->ID}'
data-image-id='{$image_id}'>
Görseli Güncelle / Ata
</button>
</td>";
echo "</tr>";
}
}
if ($found_count === 0) {
echo "<tr><td colspan='4' style='padding:40px; text-align:center;'>Eşleşen dosya bulunamadı veya tüm işlemler tamamlandı.</td></tr>";
}
?>
</tbody>
</table>
</div>
<script>
jQuery(document).ready(function($) {
$('.do-assign').on('click', function(e) {
e.preventDefault();
var btn = $(this);
var postId = btn.data('post-id');
var imageId = btn.data('image-id');
var row = $('#post-row-' + postId);
if (!confirm('Bu görseli öne çıkan görsel olarak atamak istediğinize emin misiniz?')) return;
btn.text('İşleniyor...').prop('disabled', true);
$.post(ajaxurl, {
action: 'set_featured_image_ajax',
post_id: postId,
image_id: imageId,
nonce: '<?php echo $nonce; ?>'
}, function(res) {
if(res.success) {
row.css('background', '#d4edda').fadeOut(800, function() {
$(this).remove();
if ($('#match-list tr').length === 0) {
$('#match-list').append("<tr><td colspan='4' style='padding:40px; text-align:center;'>Tüm işlemler bitti!</td></tr>");
}
});
} else {
alert('Hata: ' + (res.data || 'Bir sorun oluştu.'));
btn.text('Tekrar Dene').prop('disabled', false);
}
}).fail(function() {
alert('Sunucu hatası! Lütfen tekrar deneyin.');
btn.text('Hata! Tekrar Dene').prop('disabled', false);
});
});
});
</script>
<?php
}
/**
* Ajax İşlemi: Öne Çıkan Görseli Ata
*/
add_action('wp_ajax_set_featured_image_ajax', function() {
// Güvenlik kontrolü
check_ajax_referer('assign_nonce', 'nonce');
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
$image_id = isset($_POST['image_id']) ? intval($_POST['image_id']) : 0;
if ($post_id > 0 && $image_id > 0) {
// set_post_thumbnail() başarılı olursa true döner
$updated = set_post_thumbnail($post_id, $image_id);
if ($updated) {
wp_send_json_success();
} else {
wp_send_json_error('Görsel veritabanına kaydedilemedi.');
}
} else {
wp_send_json_error('Geçersiz Post veya Görsel ID.');
}
});Bu kodu çalıştırmak için WordPress tema dosyaları içinde yer alan functions.php dosyasını kullanabilirsiniz. Öncelikle WordPress admin paneline giriş yapın ve Görünüm → Tema Dosya Düzenleyici bölümüne gidin. Sağ tarafta bulunan dosya listesinde functions.php dosyasını bulun ve açın.
Açılan dosyanın en alt kısmına, verdiğiniz görsel eşleştirme kodunu eksiksiz şekilde yapıştırın. Kodun başında veya sonunda ekstra boşluk ya da hatalı karakter olmamasına dikkat edin. Ardından “Dosyayı Güncelle” butonuna tıklayarak değişiklikleri kaydedin.
Bu işlemi tamamladıktan sonra admin paneli yenilendiğinde sol menüde “Görsel Eşleştir” sekmesinin eklendiğini göreceksiniz. Bu sayfa üzerinden yazılarınızı tarayabilir ve tek tıkla öne çıkan görselleri atayabilirsiniz.
Aynı Sluga Sahip Görselleri Toplu Öne Çıkar (Tek Sefer İşlem)

Eğer tek, tek uğraşmayayım öne çıkan görseli olmayan eşleşen resimleri hep birden yapsın dersiniz bu kodu kullanabilirsiniz.
add_action('admin_menu', function() {
add_menu_page('Görsel Eşleştirici', 'Görsel Eşleştir', 'manage_options', 'image-matcher', 'render_image_matcher_page', 'dashicons-images-alt2');
});
function render_image_matcher_page() {
global $wpdb;
$nonce = wp_create_nonce("assign_nonce");
?>
<div class="wrap">
<h1>Görsel Eşleştirme Paneli</h1>
<div class="notice notice-info" style="display: flex; justify-content: space-between; align-items: center; padding: 15px;">
<div>
<p style="margin:0;">Sistem sadece <b>öne çıkan görseli olmayan</b> yazıları listeler ve eşleştirir.</p>
<small>Mevcut görseli olan yazılara dokunulmaz.</small>
</div>
<button id="run-bulk-action" class="button button-hero button-primary">
Sadece Eksikleri Tamamla
</button>
</div>
<div id="bulk-progress" style="display:none; background: #fff; padding: 15px; border: 1px solid #ccc; margin-bottom: 20px; border-radius: 4px;">
<div style="font-weight: bold; margin-bottom: 8px;">İşlem Durumu: <span id="progress-text">Bekliyor...</span></div>
<div style="width: 100%; background: #eee; height: 12px; border-radius: 6px; overflow: hidden;">
<div id="progress-bar" style="width: 0%; background: #2271b1; height: 100%; transition: width 0.3s;"></div>
</div>
</div>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th style="width:80px;">Yeni Görsel</th>
<th>Yazı Başlığı</th>
<th>Eşleşen Dosya</th>
<th style="width:150px;">Durum</th>
</tr>
</thead>
<tbody id="match-list">
<?php
// Yazıları çek
$posts = get_posts(['post_type' => 'post', 'posts_per_page' => -1, 'post_status' => 'publish']);
$found_count = 0;
foreach ($posts as $post) {
// KRİTİK KONTROL: Eğer zaten öne çıkan görseli varsa bu yazıyı ATLA
if (has_post_thumbnail($post->ID)) {
continue;
}
$slug = $post->post_name;
$attachment = $wpdb->get_row($wpdb->prepare(
"SELECT post_id, meta_value FROM {$wpdb->postmeta}
WHERE meta_key = '_wp_attached_file' AND meta_value LIKE %s LIMIT 1",
'%' . $wpdb->esc_like($slug) . '%'
));
if ($attachment) {
$found_count++;
$image_url = wp_get_attachment_thumb_url($attachment->post_id);
echo "<tr id='post-row-{$post->ID}' class='match-row' data-post-id='{$post->ID}' data-image-id='{$attachment->post_id}'>
<td><img src='{$image_url}' width='50' height='50' style='object-fit:cover; border-radius:3px;'></td>
<td><strong>" . esc_html($post->post_title) . "</strong></td>
<td><code>" . esc_html($attachment->meta_value) . "</code></td>
<td class='status-cell'><span class='dashicons dashicons-warning' style='color:#f39c12;'></span> Atanmaya Hazır</td>
</tr>";
}
}
if ($found_count === 0) {
echo "<tr><td colspan='4' style='padding:40px; text-align:center;'>Görseli eksik ve eşleşen dosyası olan yazı bulunamadı.</td></tr>";
}
?>
</tbody>
</table>
</div>
<script>
jQuery(document).ready(function($) {
var rows = $('.match-row');
var total = rows.length;
var processed = 0;
$('#run-bulk-action').click(function() {
if (total === 0) return alert('İşlem yapılacak yazı bulunamadı.');
if (!confirm(total + ' adet boş görselli yazı güncellenecek. Başlasın mı?')) return;
$(this).prop('disabled', true).text('İşleniyor...');
$('#bulk-progress').show();
processNext();
});
function processNext() {
var row = $('.match-row').not('.processed').first();
if (row.length === 0) {
$('#progress-text').text('Tüm eksikler tamamlandı!');
$('#run-bulk-action').text('İşlem Başarıyla Bitti');
return;
}
var postId = row.data('post-id');
var imageId = row.data('image-id');
var statusCell = row.find('.status-cell');
statusCell.html('<span class="dashicons dashicons-update spin"></span> Yazılıyor...');
$.post(ajaxurl, {
action: 'match_missing_images',
post_id: postId,
image_id: imageId,
nonce: '<?php echo $nonce; ?>'
}, function(res) {
processed++;
var percent = (processed / total) * 100;
$('#progress-bar').css('width', percent + '%');
$('#progress-text').text(processed + ' / ' + total);
if(res.success) {
statusCell.html('<span style="color:green;"><span class="dashicons dashicons-yes"></span> Atandı</span>');
row.addClass('processed').css('background', '#f0fff0');
} else {
statusCell.html('<span style="color:red;"><span class="dashicons dashicons-no"></span> Hata</span>');
row.addClass('processed');
}
setTimeout(processNext, 50); // Hızlı işlem için kısa bekleme
});
}
});
</script>
<style>
.spin { animation: rotation 1s infinite linear; }
@keyframes rotation { from { transform: rotate(0deg); } to { transform: rotate(359deg); } }
.match-row.processed { opacity: 0.7; }
</style>
<?php
}
/**
* Ajax: Sadece Boşsa Ata
*/
add_action('wp_ajax_match_missing_images', function() {
check_ajax_referer('assign_nonce', 'nonce');
$post_id = intval($_POST['post_id']);
$image_id = intval($_POST['image_id']);
if ($post_id > 0 && $image_id > 0) {
// Çift dikiş kontrol: Ajax geldiğinde de görseli var mı diye bakıyoruz
if (!get_post_thumbnail_id($post_id)) {
if (update_post_meta($post_id, '_thumbnail_id', $image_id)) {
wp_send_json_success();
}
} else {
// Zaten görseli varmış, işlem yapmaya gerek yok ama başarılı say
wp_send_json_success('Zaten mevcut');
}
}
wp_send_json_error();
});Bu kodunda ekleme mantığı aynı üstedeki şekilde fuctions.php uygulabilirsiniz. Eğer toplu yapacaksanız diğerini kaldırın. Kodlar çakışabilir, sadece bu kodu kullanın.