WordPress Yazı Başlığından Önce İçerik Ekleme

WordPress sitelerinde içerik yönetimi yaparken çoğu zaman her yazının başına belirli bir şey eklemek isteriz. Belki bir uyarı kutusu, belki bir reklam alanı, belki de “Bu içerik X tarihinde güncellenmiştir” gibi bir bilgi notu. Bunu her yazıya manuel olarak eklemek hem zaman kaybı hem de hata riski demek. İşte tam bu noktada functions.php devreye giriyor ve hayatımızı ciddi anlamda kolaylaştırıyor.

Bu yazıda WordPress’te yazı başlığından önce içerik eklemenin birden fazla yöntemini inceleyeceğiz. Hem temel hem de gelişmiş senaryoları ele alacağız, gerçek dünya örnekleriyle nasıl kullanabileceğinizi göstereceğiz.

WordPress İçerik Filtreleme Mantığı

WordPress, içeriği ekrana basmadan önce çeşitli filtrelerden geçirir. Bu filtreler sayesinde içeriği değiştirme, ekleme veya çıkarma işlemlerini tema dosyalarına dokunmadan yapabilirsiniz. En sık kullanılan filtre the_content filtresidir.

the_content filtresi, yazı içeriği ekrana basılmadan hemen önce çalışır. Bu filtreye eklediğiniz fonksiyon, içeriği alır, üzerinde değişiklik yapar ve geri döndürür. Temel mantık şu şekilde işler:

  • WordPress veritabanından yazı içeriğini çeker
  • the_content filtresine kayıtlı tüm fonksiyonları sırayla çalıştırır
  • Sonucu ekrana basar

Bu yaklaşımın güzel yanı şu: Tema değiştirseniz bile fonksiyonlarınız functions.php içinde kaldığı sürece çalışmaya devam eder. Tabii eğer child theme kullanıyorsanız ve functions.php‘yi oraya koydaysanız, ana tema güncellemelerinden etkilenmezsiniz.

Temel Kullanım: Her Yazıya İçerik Ekleme

En basit senaryodan başlayalım. Tüm yazıların başına bir metin eklemek istiyorsunuz diyelim.

// functions.php dosyasına ekleyin
function basliga_once_icerik_ekle($content) {
    if (is_single()) {
        $eklenecek_icerik = '<div class="yazi-uyari">
            <p>Bu yazı bilgilendirme amaçlıdır. Herhangi bir sorunuz için iletişime geçebilirsiniz.</p>
        </div>';
        $content = $eklenecek_icerik . $content;
    }
    return $content;
}
add_filter('the_content', 'basliga_once_icerik_ekle');

Burada dikkat edilmesi gereken birkaç nokta var. is_single() kontrolü çok önemli. Bu olmadan filtre, sayfa listeleri, widget’lar, öne çıkan içerikler dahil her yerde çalışır. Bu da beklenmedik sonuçlar doğurabilir.

$content değişkenini döndürmeyi unutmayın. Bunu atlarsanız tüm yazı içeriği kaybolur ve sayfanız boş görünür. Başlangıçta yapılan klasik hatalardan biridir.

Sadece Belirli Post Type’larda Çalıştırma

Gerçek dünyada çoğu zaman tüm yazılara değil, sadece belirli türdeki yazılara içerik eklemek isteriz. Örneğin sadece normal blog yazılarına eklemek istiyorsunuz ama sayfalar veya WooCommerce ürünlerine eklememek istiyorsunuz.

function post_tipine_gore_icerik_ekle($content) {
    global $post;
    
    // Sadece 'post' tipindeki yazılarda çalış
    if (is_single() && get_post_type($post) === 'post') {
        $yazar_adi = get_the_author();
        $yayin_tarihi = get_the_date('d F Y');
        
        $bilgi_kutusu = '<div class="yazar-bilgi-kutusu" style="background:#f5f5f5; padding:15px; margin-bottom:20px; border-left:4px solid #0073aa;">
            <p><strong>Yazar:</strong> ' . esc_html($yazar_adi) . '</p>
            <p><strong>Yayın Tarihi:</strong> ' . esc_html($yayin_tarihi) . '</p>
        </div>';
        
        $content = $bilgi_kutusu . $content;
    }
    
    return $content;
}
add_filter('the_content', 'post_tipine_gore_icerik_ekle');

Bu örnekte get_post_type() kullanarak yazı tipini kontrol ediyoruz. global $post ile mevcut yazı nesnesine erişiyoruz. Bunun yanında esc_html() kullanarak güvenlik önlemi alıyoruz; dinamik içeriklerde her zaman sanitize etmeyi alışkanlık haline getirin.

Kategori Bazlı İçerik Ekleme

Diyelim ki “teknoloji” kategorisindeki yazıların başına “Bu içerik teknik bilgi gerektirebilir” şeklinde bir uyarı koymak istiyorsunuz. Ya da belirli bir kategori için sponsor içerik bildirimi eklemek istiyorsunuz.

function kategori_bazli_icerik_ekle($content) {
    if (!is_single()) {
        return $content;
    }
    
    // Belirli kategorileri kontrol et
    $hedef_kategoriler = array('teknoloji', 'yazilim', 'linux');
    
    if (has_category($hedef_kategoriler)) {
        $teknik_uyari = '<div class="teknik-icerik-uyari" style="background:#fff3cd; border:1px solid #ffc107; padding:12px 15px; margin-bottom:25px; border-radius:4px;">
            <strong>Teknik İçerik:</strong> Bu makale önceden teknik bilgi gerektiren konular içermektedir. 
            Konuya yabancıysanız temel kaynaklara göz atmanızı öneririz.
        </div>';
        
        $content = $teknik_uyari . $content;
    }
    
    // Sponsorlu içerik kategorisi
    if (has_category('sponsorlu')) {
        $sponsorlu_bildirim = '<div class="sponsorlu-icerik" style="background:#e8f4f8; border:1px solid #bee5eb; padding:10px 15px; margin-bottom:20px; border-radius:4px;">
            <strong>Reklam:</strong> Bu içerik sponsorlu bir içeriktir.
        </div>';
        
        $content = $sponsorlu_bildirim . $content;
    }
    
    return $content;
}
add_filter('the_content', 'kategori_bazli_icerik_ekle');

has_category() fonksiyonu hem kategori slug’ını hem de adını hem de ID’sini kabul eder. Dizi geçerek birden fazla kategoriyi aynı anda kontrol edebilirsiniz.

Custom Field (Özel Alan) Verisiyle Dinamik İçerik

Gerçek dünyada en çok işe yarayan senaryolardan biri budur. Her yazı için farklı bir başlık öncesi mesaj göstermek isteyebilirsiniz. Bunun için custom field kullanımı idealdir.

function custom_field_ile_dinamik_icerik($content) {
    if (!is_single()) {
        return $content;
    }
    
    global $post;
    
    // Özel alanı kontrol et
    $ozel_mesaj = get_post_meta($post->ID, 'yazi_basi_mesaji', true);
    $guncelleme_tarihi = get_post_meta($post->ID, 'son_guncelleme', true);
    
    $on_icerik = '';
    
    // Güncelleme tarihi varsa ekle
    if (!empty($guncelleme_tarihi)) {
        $on_icerik .= '<div class="guncelleme-notu" style="background:#d4edda; border:1px solid #c3e6cb; padding:10px 15px; margin-bottom:15px; border-radius:4px;">
            <strong>Son Güncelleme:</strong> ' . esc_html($guncelleme_tarihi) . '
        </div>';
    }
    
    // Özel mesaj varsa ekle
    if (!empty($ozel_mesaj)) {
        $on_icerik .= '<div class="ozel-mesaj-kutusu" style="background:#cce5ff; border:1px solid #b8daff; padding:12px 15px; margin-bottom:20px; border-radius:4px;">
            ' . wp_kses_post($ozel_mesaj) . '
        </div>';
    }
    
    return $on_icerik . $content;
}
add_filter('the_content', 'custom_field_ile_dinamik_icerik');

Bu yaklaşım sayesinde her yazı için admin panelinden farklı bir başlık öncesi mesaj girebilirsiniz. wp_kses_post() burada özellikle önemli; çünkü admin tarafından girilen içerik HTML içerebilir, bu fonksiyon güvenli HTML taglarına izin verirken tehlikeli olanları temizler.

Belirli Yazıları Hariç Tutma

Bazen genel bir kural koyarsınız ama bazı yazıları bu kuralın dışında tutmak istersiniz. Örneğin 100 yazının tamamına bir şey ekleyeceksiniz ama 5 tanesini hariç tutmak istiyorsunuz.

function haric_tutarak_icerik_ekle($content) {
    if (!is_single()) {
        return $content;
    }
    
    global $post;
    
    // Hariç tutulacak yazı ID'leri
    $haric_yazlar = array(42, 87, 156, 203, 441);
    
    if (in_array($post->ID, $haric_yazlar)) {
        return $content;
    }
    
    // Ayrıca custom field ile de hariç tutma imkanı
    $haric_tut = get_post_meta($post->ID, 'on_icerik_gizle', true);
    if ($haric_tut === 'evet') {
        return $content;
    }
    
    $standart_bilgi = '<div class="site-bilgi-notu" style="background:#f8f9fa; border:1px solid #dee2e6; padding:12px 15px; margin-bottom:20px; border-radius:4px; font-size:14px;">
        Bu sitedeki tüm içerikler <strong>Creative Commons</strong> lisansı altında yayınlanmaktadır.
        Kaynak göstererek paylaşabilirsiniz.
    </div>';
    
    return $standart_bilgi . $content;
}
add_filter('the_content', 'haric_tutarak_icerik_ekle');

Custom field yaklaşımı burada özellikle pratik. Yazı editörüne on_icerik_gizle adında bir custom field ekleyip değerini evet yapınca o yazıda içerik görünmüyor. ID bazlı kontrol ise statik ama hızlı bir çözüm.

Okuma Süresi Hesaplayıp Gösterme

Popüler bir özellik olan okuma süresi göstergesini yazı başına ekleyelim. Medium gibi platformlarda gördüğünüz bu özelliği WordPress’e kolayca entegre edebilirsiniz.

function okuma_suresi_ekle($content) {
    if (!is_single() || get_post_type() !== 'post') {
        return $content;
    }
    
    // Kelime sayısını hesapla
    $kelime_sayisi = str_word_count(strip_tags($content));
    
    // Ortalama okuma hızı: dakikada 200 kelime
    $okuma_dakika = ceil($kelime_sayisi / 200);
    
    // Süreyi metne çevir
    if ($okuma_dakika < 1) {
        $sure_metni = '1 dakikadan az';
    } elseif ($okuma_dakika === 1) {
        $sure_metni = '1 dakika';
    } else {
        $sure_metni = $okuma_dakika . ' dakika';
    }
    
    $okuma_suresi_html = '<div class="okuma-suresi-bilgisi" style="display:flex; align-items:center; gap:8px; color:#666; font-size:14px; margin-bottom:20px; padding:8px 0; border-bottom:1px solid #eee;">
        <span>Tahmini Okuma Süresi:</span>
        <strong style="color:#333;">' . esc_html($sure_metni) . '</strong>
        <span>(' . number_format($kelime_sayisi) . ' kelime)</span>
    </div>';
    
    return $okuma_suresi_html . $content;
}
add_filter('the_content', 'okuma_suresi_ekle');

str_word_count() PHP’nin yerleşik fonksiyonu, ancak Türkçe karakterlerle bazen tutarsız sonuçlar verebilir. Daha hassas bir hesaplama için preg_split() kullanabilirsiniz. Yine de yaklaşık bir değer için bu yöntem yeterince iyi çalışır.

Çoklu Koşullu Gelişmiş Senaryo

Şimdi gerçek hayatta karşılaşabileceğiniz daha karmaşık bir senaryo ele alalım. Diyelim ki bir haber sitesi işletiyorsunuz ve şu koşulları sağlamanız gerekiyor:

  • Yazarın yetkisine göre farklı içerik göster
  • Giriş yapmış kullanıcılara farklı mesaj göster
  • Eski yazılar için güncelleme uyarısı ekle
function gelismis_kosullu_icerik_ekle($content) {
    if (!is_single()) {
        return $content;
    }
    
    global $post;
    $on_icerik = '';
    
    // Eski yazı kontrolü (2 yıldan eski)
    $yayin_zamani = get_the_time('U');
    $iki_yil_once = strtotime('-2 years');
    
    if ($yayin_zamani < $iki_yil_once) {
        $gecen_sure = human_time_diff($yayin_zamani, current_time('timestamp'));
        
        $on_icerik .= '<div class="eski-yazi-uyarisi" style="background:#fff3cd; border-left:4px solid #ffc107; padding:12px 15px; margin-bottom:15px;">
            <strong>Dikkat:</strong> Bu yazı ' . esc_html($gecen_sure) . ' önce yayınlanmıştır. 
            Bazı bilgiler güncelliğini yitirmiş olabilir.
        </div>';
    }
    
    // Giriş yapmamış kullanıcılar için kayıt daveti
    if (!is_user_logged_in()) {
        $on_icerik .= '<div class="kayit-daveti" style="background:#e8f4f8; border:1px solid #bee5eb; padding:12px 15px; margin-bottom:15px; border-radius:4px;">
            <strong>Topluluğumuza Katılın:</strong> 
            <a href="' . esc_url(wp_registration_url()) . '">Üye olun</a> 
            ve tüm içeriklere erişin, yorum yapın.
        </div>';
    }
    
    // Editör veya admin tarafından yazılmışsa rozet ekle
    $yazar_id = $post->post_author;
    if (user_can($yazar_id, 'edit_others_posts')) {
        $yazar_adi = get_the_author_meta('display_name', $yazar_id);
        
        $on_icerik .= '<div class="editör-rozeti" style="display:inline-block; background:#0073aa; color:white; font-size:12px; padding:3px 8px; border-radius:3px; margin-bottom:15px;">
            Editör İçeriği: ' . esc_html($yazar_adi) . '
        </div><br>';
    }
    
    return $on_icerik . $content;
}
add_filter('the_content', 'gelismis_kosullu_icerik_ekle');

Bu örnek gerçek dünyada çok karşılaşılan senaryoları bir araya getiriyor. human_time_diff() fonksiyonu “3 yıl önce” gibi insan dostu zaman ifadeleri üretiyor. user_can() ile herhangi bir kullanıcının yetkisini kontrol edebiliyorsunuz.

Priority (Öncelik) Değerinin Önemi

add_filter kullanırken dördüncü parametre olan öncelik değerini çoğu kişi göz ardı eder, ama bu değer çok kritik olabilir.

// Düşük priority = önce çalışır (varsayılan 10)
add_filter('the_content', 'once_calisacak_fonksiyon', 5);

// Yüksek priority = sonra çalışır
add_filter('the_content', 'sonra_calisacak_fonksiyon', 20);

// Örnek: Hem uyarı hem okuma süresi ekleyecekseniz
function uyari_kutusu_ekle($content) {
    if (!is_single()) return $content;
    
    $uyari = '<div class="genel-uyari" style="background:#f8d7da; border:1px solid #f5c6cb; padding:10px 15px; margin-bottom:15px; border-radius:4px;">
        <strong>Önemli:</strong> Bu sitedeki içerikler düzenli güncellenir.
    </div>';
    
    return $uyari . $content;
}

function okuma_bilgisi_ekle($content) {
    if (!is_single()) return $content;
    
    $kelime = str_word_count(strip_tags($content));
    $sure = ceil($kelime / 200);
    
    $bilgi = '<p style="color:#666; font-size:13px; margin-bottom:10px;">Okuma süresi: ' . $sure . ' dakika</p>';
    
    return $bilgi . $content;
}

// Okuma bilgisi önce, sonra uyarı kutusu gelsin
add_filter('the_content', 'uyari_kutusu_ekle', 10);
add_filter('the_content', 'okuma_bilgisi_ekle', 11);

Burada priority 10 ile eklenen uyari_kutusu_ekle önce çalışır. Sonra priority 11 ile okuma_bilgisi_ekle çalışır. İkincisi $content‘i alır ki bu noktada içerik zaten uyarı kutusunu içeriyor. Bu sayede okuma bilgisi, uyarı kutusundan önce çıkar sayfada.

Performans Optimizasyonu

Filtreleri yazarken performansı da göz önünde bulundurmalısınız. Her sayfa yüklendiğinde bu kodlar çalışır.

function performans_odakli_icerik_ekle($content) {
    // İlk check: is_admin kontrolü
    if (is_admin()) {
        return $content;
    }
    
    // Loop dışında olduğumuzdan emin ol
    if (!in_the_loop()) {
        return $content;
    }
    
    // Post type kontrolü - en hızlı kontrol başta yapılmalı
    if (!is_singular('post')) {
        return $content;
    }
    
    // Transient ile cache - aynı içeriği tekrar hesaplamaktan kaçın
    global $post;
    $cache_key = 'on_icerik_' . $post->ID;
    $cached = get_transient($cache_key);
    
    if ($cached !== false) {
        return $cached . $content;
    }
    
    // Hesaplama yap
    $kelime_sayisi = str_word_count(strip_tags($content));
    $sure = ceil($kelime_sayisi / 200);
    
    $on_icerik = '<div class="meta-bilgi" style="color:#666; font-size:13px; padding:8px 0; border-bottom:1px solid #eee; margin-bottom:20px;">
        Okuma süresi: ' . $sure . ' dk | ' . number_format($kelime_sayisi) . ' kelime
    </div>';
    
    // 12 saat cache'le
    set_transient($cache_key, $on_icerik, 12 * HOUR_IN_SECONDS);
    
    return $on_icerik . $content;
}
add_filter('the_content', 'performans_odakli_icerik_ekle');

// Yazı güncellenince cache'i temizle
function on_icerik_cache_temizle($post_id) {
    delete_transient('on_icerik_' . $post_id);
}
add_action('save_post', 'on_icerik_cache_temizle');

in_the_loop() kontrolü önemli. Bu olmadan filtre, the_content() fonksiyonunun çağrıldığı her yerde çalışır; sidebar widget’ları, Related Posts pluginleri dahil. Transient kullanımı ise özellikle okuma süresi hesabı gibi tekrar hesaplamaya gerek olmayan şeyler için değerli.

Sık Yapılan Hatalar ve Çözümleri

Birkaç yaygın sorundan bahsedelim:

İçerik kaybolması: $content‘i return etmeyi unutmak en klasik hata. Fonksiyon bir şey döndürmezse null döner ve içerik tamamen kaybolur.

Her yerde çalışması: is_single(), is_singular() veya in_the_loop() kontrolü yapmadan eklenen filtreler beklenmedik yerlerde çalışır. Arama sonuçları, RSS feed’i, excerpt’ler bu durumdan etkilenebilir.

XSS açıkları: Dinamik veri içerirken esc_html(), esc_url(), wp_kses_post() gibi sanitize fonksiyonlarını kullanmayı ihmal etmek ciddi güvenlik açıklarına yol açar.

Çakışan eklentiler: Başka bir eklenti de aynı filtreyi kullanıyorsa çakışma olabilir. Priority değerlerini bilinçli seçerek bu sorunu minimize edebilirsiniz.

Loop dışı çalışma: Bazı sayfa yapılarında the_content filtresi loop dışında da tetiklenebilir. in_the_loop() kontrolü bunu önler.

Sonuç

WordPress the_content filtresi, tema dosyalarına dokunmadan içerik yönetiminde inanılmaz esneklik sağlar. Yazı başına uyarı kutuları, okuma süresi göstergeleri, yazar bilgileri, sponsorlu içerik bildirimleri gibi onlarca kullanım senaryosu için tek bir filtre mekanizması yeterli oluyor.

Önemli olan doğru koşulları kontrol etmek: is_single(), in_the_loop(), post type kontrolü. Güvenliği ihmal etmemek: dinamik veri her zaman escape edilmeli. Performansı düşünmek: sık hesaplanan veriler için transient cache kullanmak iyi bir alışkanlık.

Bu teknikleri child theme’inizin functions.php dosyasına ekleyerek kullanmanızı tavsiye ederim. Ana tema güncellemelerinden bağımsız kalırsınız ve kodlarınız güvende olur. Kodu yazdıktan sonra mobil dahil farklı görünümlerde test etmeyi ve mümkünse bir staging ortamında denemeyi ihmal etmeyin.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir