WordPress Loop Öncesine ve Sonrasına İçerik Ekleme

WordPress geliştirme sürecinde en çok ihtiyaç duyulan şeylerden biri, sayfa içeriğini dinamik olarak kontrol etmektir. Özellikle loop yani döngü öncesine ve sonrasına içerik eklemek, tema dosyalarına dokunmadan işlevsellik kazandırmanın en temiz yollarından biridir. functions.php dosyası bu noktada devreye girer ve bize güçlü kancalar (hooks) aracılığıyla içerik yönetimi imkânı sunar.

Bu yazıda, WordPress’in the_content filtresini, loop_start ve loop_end aksiyonlarını ve daha fazlasını kullanarak loop öncesine ve sonrasına nasıl içerik ekleyeceğimizi gerçek dünya senaryolarıyla ele alacağız.

WordPress Loop Nedir ve Neden Önemlidir?

WordPress’in temel çalışma prensibi loop üzerine kuruludur. Bir sayfa ya da yazı görüntülendiğinde, WordPress veritabanından içeriği çeker ve bu döngü içinde işler. Loop, while (have_posts()) : the_post(); yapısıyla başlar ve tüm içerik bu döngü sayesinde render edilir.

Buraya içerik eklemek istediğinizde iki temel yaklaşım vardır:

  • Tema dosyalarını doğrudan düzenlemek (kötü pratik, güncellemelerde kaybolur)
  • functions.php içinde hook ve filtreler kullanmak (doğru yaklaşım)

Hook tabanlı yaklaşım, temanız güncellendiğinde ya da değiştirildiğinde bile özelleştirmelerinizin kaybolmamasını sağlar. Bu yüzden her zaman functions.php veya özel bir eklenti dosyası tercih edilmelidir.

the_content Filtresi ile İçerik Ekleme

En temel ve en çok kullanılan yöntem the_content filtresidir. Bu filtre, WordPress her yazı ya da sayfa içeriğini ekrana basmadan önce devreye girer ve içeriği değiştirmenize olanak tanır.

Basit Bir Örnek: Yazı Başına ve Sonuna Mesaj Ekleme

<?php
function sysadmin_icerik_ekle($content) {
    if (is_single() && in_the_loop() && is_main_query()) {
        $oncesi = '<div class="yazi-oncesi">
            <p>Bu içerik yalnızca bilgilendirme amaçlıdır.</p>
        </div>';

        $sonrasi = '<div class="yazi-sonrasi">
            <p>Bu yazıyı faydalı buldunuz mu? Yorum yazmayı unutmayın!</p>
        </div>';

        $content = $oncesi . $content . $sonrasi;
    }
    return $content;
}
add_filter('the_content', 'sysadmin_icerik_ekle');

Burada dikkat edilmesi gereken kritik nokta şudur: is_single(), in_the_loop() ve is_main_query() kontrollerini yapmadan her yerde bu kod çalışır. Widget alanlarında, menülerde ya da başka döngülerde de tetiklenerek beklenmedik çıktılar üretebilir.

Koşullu İçerik Ekleme: Yazı Türüne Göre Farklı İçerik

Gerçek dünyada genellikle belirli yazı türleri için farklı içerikler eklemek gerekir. Örneğin sadece “tutorial” kategorisindeki yazılara bilgi kutusu eklemek istiyorsunuz:

<?php
function sysadmin_kategori_bazli_icerik($content) {
    if (!is_single() || !in_the_loop() || !is_main_query()) {
        return $content;
    }

    if (has_category('tutorial')) {
        $bilgi_kutusu = '<div class="bilgi-kutusu" style="background:#f0f8ff; 
            border-left:4px solid #0073aa; padding:15px; margin-bottom:20px;">
            <strong>Bu bir eğitim yazısıdır.</strong> 
            Adımları sırayla takip etmenizi öneririz.
        </div>';
        $content = $bilgi_kutusu . $content;
    }

    if (has_tag('guvenlik')) {
        $uyari = '<div class="uyari-kutusu" style="background:#fff3cd; 
            border-left:4px solid #ffc107; padding:15px; margin-top:20px;">
            <strong>Güvenlik Notu:</strong> Bu yazıdaki komutları 
            production ortamında uygulamadan önce test ediniz.
        </div>';
        $content = $content . $uyari;
    }

    return $content;
}
add_filter('the_content', 'sysadmin_kategori_bazli_icerik');

Bu örnek özellikle sysadmin bloglarında son derece kullanışlıdır. “güvenlik” etiketli yazıların altına otomatik uyarı eklemek, okuyucunuzu korur ve içeriklerinizi daha profesyonel gösterir.

loop_start ve loop_end Aksiyonları

the_content filtresi tek bir yazının içeriğini etkilerken, loop_start ve loop_end aksiyonları tüm döngü yapısını hedefler. Bu yöntem özellikle arşiv sayfaları, kategori listeleri ve arama sonuçları için idealdir.

loop_start Kullanımı

<?php
function sysadmin_loop_oncesi_icerik($query) {
    if (!is_admin() && $query->is_main_query()) {
        if (is_category('haberler')) {
            echo '<div class="haber-banner">
                <p>Son dakika haberleri aşağıda listelenmektedir.</p>
            </div>';
        }
        
        if (is_search()) {
            $arama_terimi = get_search_query();
            echo '<div class="arama-bilgi">
                <p><strong>"' . esc_html($arama_terimi) . '"</strong> 
                için arama sonuçları:</p>
            </div>';
        }
    }
}
add_action('loop_start', 'sysadmin_loop_oncesi_icerik');

loop_end Kullanımı

<?php
function sysadmin_loop_sonrasi_icerik($query) {
    if (!is_admin() && $query->is_main_query()) {
        if (is_category() || is_tag() || is_archive()) {
            echo '<div class="arsiv-sonrasi">
                <div style="background:#f9f9f9; padding:20px; 
                    border-radius:5px; margin-top:30px;">
                    <h3>Bültenimize Abone Olun</h3>
                    <p>Yeni yazılardan haberdar olmak için 
                    e-posta listemize katılın.</p>
                </div>
            </div>';
        }
    }
}
add_action('loop_end', 'sysadmin_loop_sonrasi_icerik');

loop_start ve loop_end aksiyonlarına $query nesnesi parametre olarak geçer. Bu sayede hangi sorgu için döngünün başladığını veya bittiğini kontrol edebilirsiniz.

Gerçek Dünya Senaryosu: Yazı Sonu Yazar Kartı

Bir blog için en yaygın ihtiyaçlardan biri, yazı sonunda yazar hakkında bilgi kartı göstermektir. Bunu her tema dosyasına eklemek yerine functions.php üzerinden yönetmek çok daha sürdürülebilirdir:

<?php
function sysadmin_yazar_karti($content) {
    if (!is_single() || !in_the_loop() || !is_main_query()) {
        return $content;
    }

    $yazar_id    = get_the_author_meta('ID');
    $yazar_adi   = get_the_author_meta('display_name');
    $yazar_bio   = get_the_author_meta('description');
    $yazar_url   = get_author_posts_url($yazar_id);
    $yazar_avatar = get_avatar($yazar_id, 80);

    if (empty($yazar_bio)) {
        return $content;
    }

    $kart = '<div class="yazar-karti" style="display:flex; gap:20px; 
        padding:20px; background:#f9f9f9; border-radius:8px; 
        margin-top:40px; border:1px solid #e0e0e0;">
        <div class="yazar-avatar">' . $yazar_avatar . '</div>
        <div class="yazar-bilgi">
            <h4 style="margin:0 0 10px 0;">
                <a href="' . esc_url($yazar_url) . '">' . 
                esc_html($yazar_adi) . '</a>
            </h4>
            <p style="margin:0; color:#555;">' . 
            esc_html($yazar_bio) . '</p>
        </div>
    </div>';

    return $content . $kart;
}
add_filter('the_content', 'sysadmin_yazar_karti', 20);

Burada add_filter fonksiyonunun üçüncü parametresi olan 20 öncelik değerine dikkat edin. Varsayılan değer 10‘dur. Yazar kartını diğer içerik filtrelerinden sonra çalıştırmak için daha yüksek bir öncelik değeri kullandık.

Öncelik Yönetimi ve Çakışmaların Önlenmesi

Birden fazla filtre aynı hook’a bağlandığında sıralama kritik önem taşır. WordPress, filtre önceliğini şu şekilde işler:

  • Düşük sayı: Erken çalışır (önce)
  • Yüksek sayı: Geç çalışır (sonra)
  • Varsayılan: 10 öncelik değeri

Örneğin iki farklı içerik bloğunu belirli bir sıraya koymak istiyorsanız:

<?php
// Önce çalışır - Öncelik 5
function sysadmin_uyari_mesaji($content) {
    if (is_single() && in_the_loop() && is_main_query()) {
        $uyari = '<div class="uyari">Okumadan önce dikkat!</div>';
        $content = $uyari . $content;
    }
    return $content;
}
add_filter('the_content', 'sysadmin_uyari_mesaji', 5);

// Sonra çalışır - Öncelik 15
function sysadmin_paylasim_butonlari($content) {
    if (is_single() && in_the_loop() && is_main_query()) {
        $butonlar = '<div class="paylasim">
            <a href="#">Twitter'da Paylaş</a> | 
            <a href="#">LinkedIn'de Paylaş</a>
        </div>';
        $content = $content . $butonlar;
    }
    return $content;
}
add_filter('the_content', 'sysadmin_paylasim_butonlari', 15);

Sayfa Türüne Göre Dinamik İçerik

Sadece blog yazıları değil, özel sayfa şablonları için de benzer yaklaşımları kullanabilirsiniz. Aşağıdaki örnek, “hizmetler” adlı sayfa için özel bir çağrı-to-aksiyon bloğu ekler:

<?php
function sysadmin_hizmet_sayfasi_icerik($content) {
    if (!is_page() || !in_the_loop() || !is_main_query()) {
        return $content;
    }

    global $post;
    $sayfa_slug = $post->post_name;

    if ($sayfa_slug === 'hizmetler') {
        $cta_oncesi = '<div class="hizmet-intro" style="background:#e8f4fd; 
            padding:15px; border-radius:5px; margin-bottom:25px;">
            <p>Profesyonel çözümlerimizi keşfedin. 
            7/24 destek için bize ulaşın.</p>
        </div>';

        $cta_sonrasi = '<div class="hizmet-cta" style="text-align:center; 
            padding:30px; background:#0073aa; color:#fff; 
            border-radius:8px; margin-top:30px;">
            <h3 style="color:#fff;">Hemen Başlayalım</h3>
            <p>Ücretsiz danışmanlık için formumuzu doldurun.</p>
            <a href="/iletisim" style="background:#fff; color:#0073aa; 
                padding:10px 25px; border-radius:4px; 
                text-decoration:none; font-weight:bold;">
                İletişime Geç
            </a>
        </div>';

        $content = $cta_oncesi . $content . $cta_sonrasi;
    }

    return $content;
}
add_filter('the_content', 'sysadmin_hizmet_sayfasi_icerik');

Gelişmiş Senaryo: Özel Post Type Desteği

WooCommerce ya da özel post type kullanıyorsanız, bu yapılar için de aynı teknikleri uygulayabilirsiniz. Örneğin portfolio adlı özel bir post type için:

<?php
function sysadmin_portfolio_icerik($content) {
    if (!is_singular('portfolio') || !in_the_loop() || !is_main_query()) {
        return $content;
    }

    // Özel meta alanlardan veri çek
    $proje_tarihi  = get_post_meta(get_the_ID(), 'proje_tarihi', true);
    $proje_musteri = get_post_meta(get_the_ID(), 'proje_musteri', true);
    $proje_link    = get_post_meta(get_the_ID(), 'proje_link', true);

    $meta_blok = '<div class="portfolio-meta" style="background:#fafafa; 
        border:1px solid #ddd; padding:15px; border-radius:5px; 
        margin-bottom:25px;">
        <ul style="list-style:none; margin:0; padding:0;">';

    if ($proje_tarihi) {
        $meta_blok .= '<li><strong>Tarih:</strong> ' . 
            esc_html($proje_tarihi) . '</li>';
    }
    if ($proje_musteri) {
        $meta_blok .= '<li><strong>Müşteri:</strong> ' . 
            esc_html($proje_musteri) . '</li>';
    }
    if ($proje_link) {
        $meta_blok .= '<li><strong>Canlı Link:</strong> 
            <a href="' . esc_url($proje_link) . '" target="_blank">
            Projeyi Görüntüle</a></li>';
    }

    $meta_blok .= '</ul></div>';

    $proje_sonu = '<div class="portfolio-sonrasi" style="margin-top:30px;">
        <a href="/portfolio" style="background:#333; color:#fff; 
            padding:10px 20px; border-radius:4px; text-decoration:none;">
            Tüm Projeleri Gör
        </a>
    </div>';

    return $meta_blok . $content . $proje_sonu;
}
add_filter('the_content', 'sysadmin_portfolio_icerik');

Güvenlik: XSS Saldırılarına Karşı Önlem

İçerik eklerken güvenliği asla göz ardı etmeyin. Kullanıcıdan ya da veritabanından gelen veriler her zaman temizlenmelidir:

  • esc_html(): Düz metin çıktısı için kullanın
  • esc_url(): URL’leri temizlemek için kullanın
  • esc_attr(): HTML özellik değerleri için kullanın
  • wp_kses_post(): HTML içerik geçirmek istediğinizde kullanın
<?php
function sysadmin_guvenli_icerik($content) {
    if (!is_single() || !in_the_loop() || !is_main_query()) {
        return $content;
    }

    // Kullanıcı meta verisini güvenli şekilde al
    $yazar_web    = get_the_author_meta('user_url');
    $yazar_twitter = get_the_author_meta('twitter');

    $izin_verilen_html = array(
        'a'      => array('href' => array(), 'target' => array()),
        'strong' => array(),
        'em'     => array(),
        'p'      => array(),
        'div'    => array('class' => array(), 'style' => array()),
    );

    $sosyal_blok = '<div class="sosyal-linkler">';

    if ($yazar_web) {
        $sosyal_blok .= '<a href="' . esc_url($yazar_web) . '" 
            target="_blank" rel="noopener">Web Sitesi</a>';
    }

    if ($yazar_twitter) {
        $sosyal_blok .= ' | <a href="https://twitter.com/' . 
            esc_attr($yazar_twitter) . '" target="_blank" rel="noopener">
            Twitter</a>';
    }

    $sosyal_blok .= '</div>';

    // wp_kses ile çıktıyı temizle
    return $content . wp_kses($sosyal_blok, $izin_verilen_html);
}
add_filter('the_content', 'sysadmin_guvenli_icerik', 25);

Performans İpuçları

Loop içine içerik eklerken performansı da düşünmek gerekir. Her sayfa yüklemesinde gereksiz veritabanı sorguları atmaktan kaçının:

  • Transient API kullanın: Sık değişmeyen veriler için sonuçları önbelleğe alın
  • is_main_query() kontrolü: Sadece ana döngüde çalışmasını sağlayın
  • is_admin() kontrolü: Admin panelinde gereksiz yere çalışmasını engelleyin
  • Koşullu etiketleri iç içe kullanmaktan kaçının: Her koşul bir sorgu maliyeti getirebilir

En sık yapılan hata, the_content filtresine bağlanan bir fonksiyon içinde her sayfa yüklemesinde veritabanı sorgusu çalıştırmaktır. Eğer statik bir içerik ekliyorsanız bunu direkt HTML olarak yazın, dinamik bir veri gerekiyorsa transient ile saatlerce önbellekte tutun.

Child Theme functions.php Kullanımı

Tüm bu kod örneklerini ana temanın functions.php dosyasına değil, mutlaka child theme (alt tema) functions.php dosyasına eklemelisiniz. Ana temanız güncellendiğinde tüm değişiklikleriniz silinir. Child theme kullanıyorsanız güvendesiniz.

Eğer child theme yoksa, wp-content/plugins/ dizininde kendinize ait küçük bir eklenti oluşturabilirsiniz. Bu yaklaşım aslında daha temizdir çünkü fonksiyonellik ile görsel tasarımı birbirinden ayırır.

Sonuç

WordPress loop öncesine ve sonrasına içerik eklmek göründüğünden çok daha esnektir. the_content filtresi tek bir içeriği hedef alırken, loop_start ve loop_end aksiyonları tüm döngü yapısını kapsar. Her iki yaklaşımın da kendine özgü kullanım senaryoları vardır.

Özetlemek gerekirse:

  • the_content filtresi: Tekil yazı ve sayfa içerikleri için, yazar kartı, uyarı mesajı, paylaşım butonları
  • loop_start aksiyonu: Döngü başında kategori ya da arşiv sayfalarına banner veya bilgi bloğu ekleme
  • loop_end aksiyonu: Döngü sonunda bülten aboneliği, ilgili içerik önerileri gibi bloklar
  • Güvenlik kontrolü: Her zaman esc_html(), esc_url() gibi temizleme fonksiyonları kullanın
  • Koşul kontrolü: in_the_loop() ve is_main_query() olmadan hook bağlamayın

Bu yöntemleri doğru kullandığınızda tema güncellemelerinden etkilenmeyen, bakımı kolay ve güvenli bir WordPress yapısı elde edersiniz. Kod yazmak yerine eklenti kurmak cazip gelse de, bu kadar basit özelleştirmeler için functions.php her zaman daha hafif ve kontrol edilebilir bir seçenektir.

Bir yanıt yazın

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