WordPress’te Özel Arşiv Şablonu Yönlendirme

WordPress projelerinde özel arşiv sayfaları oluştururken en sık karşılaşılan sorunlardan biri, şablon yönlendirmesinin tam olarak istediğimiz gibi çalışmamasıdır. Belki bir müşteri için özel bir portföy arşivi yapıyorsunuz, belki WooCommerce ürün kategorileri için tamamen farklı bir layout istiyorsunuz ya da custom post type’larınızın arşiv sayfalarını tema hiyerarşisinin dışına çıkararak yönetmek istiyorsunuz. İşte tam bu noktada functions.php içindeki şablon yönlendirme fonksiyonları devreye giriyor.

Bu yazıda WordPress’in şablon hiyerarşisini nasıl çalıştığını, template_include filter’ını, özel arşiv şablon yönlendirmelerini ve gerçek dünyada karşılaşılan senaryolar için pratik çözümleri ele alacağız.

WordPress Şablon Hiyerarşisi Nasıl Çalışır?

WordPress bir sayfa yüklendiğinde, hangi şablonun kullanılacağını belirlemek için belirli bir sıra izler. Arşiv sayfaları için bu sıra şu şekilde işler:

  • archive-{post_type}.php: Belirli bir post type’a özel arşiv şablonu
  • archive.php: Genel arşiv şablonu
  • index.php: Son çare şablonu

Kategori, etiket ve diğer taxonomy arşivleri için de benzer bir hiyerarşi geçerlidir:

  • taxonomy-{taxonomy}-{term}.php: Belirli bir terim için şablon
  • taxonomy-{taxonomy}.php: Belirli bir taxonomy için şablon
  • taxonomy.php: Genel taxonomy şablonu
  • archive.php: Genel arşiv şablonu

Bu hiyerarşi yeterli olmadığında ya da daha dinamik bir kontrol istediğimizde, functions.php içinde template_include filter’ını kullanarak işi eline almamız gerekiyor.

template_include Filter’ı

WordPress, şablonu yüklemeden hemen önce template_include filter’ını çalıştırır. Bu filter sayesinde yüklenecek şablonu programatik olarak değiştirebilirsiniz.

Temel kullanım şu şekildedir:

add_filter( 'template_include', 'my_custom_template_include' );

function my_custom_template_include( $template ) {
    // Koşullu kontrollerinizi buraya yazın
    // Değiştirilmiş şablon yolunu döndürün
    return $template;
}

Bu filter template_redirect action’ından farklıdır. template_redirect sizi başka bir URL’ye yönlendirirken, template_include aynı URL’de kalarak farklı bir şablon dosyası yükler. Bu ayrım çok önemlidir.

Senaryo 1: Custom Post Type Arşivini Özel Klasörden Yönlendirme

Bir müşteri projesi düşünelim. “Projeler” adında bir custom post type’ınız var ve bu arşivin şablonunu page-templates/archive-projeler.php gibi özel bir klasörde tutmak istiyorsunuz. Tema hiyerarşisini bozmadan bunu yapabilirsiniz:

add_filter( 'template_include', 'projeler_arsiv_sablonu_yonlendir' );

function projeler_arsiv_sablonu_yonlendir( $template ) {
    if ( is_post_type_archive( 'projeler' ) ) {
        $ozel_sablon = get_stylesheet_directory() . '/page-templates/archive-projeler.php';
        
        if ( file_exists( $ozel_sablon ) ) {
            return $ozel_sablon;
        }
    }
    
    return $template;
}

Bu kodda get_stylesheet_directory() kullanıyoruz. Çocuk tema kullanıyorsanız bu önemlidir. Eğer ana tema klasörünü kullanmak istiyorsanız get_template_directory() tercih edin.

Senaryo 2: Kullanıcı Rolüne Göre Farklı Arşiv Şablonu

Daha ileri gidelim. Bir üyelik sitesinde premium ve ücretsiz kullanıcılara farklı arşiv görünümleri sunmak istiyorsunuz:

add_filter( 'template_include', 'rol_bazli_arsiv_sablonu' );

function rol_bazli_arsiv_sablonu( $template ) {
    if ( ! is_archive() ) {
        return $template;
    }
    
    $kullanici = wp_get_current_user();
    
    // Premium üye kontrolü
    if ( in_array( 'premium_uye', (array) $kullanici->roles ) ) {
        $premium_sablon = get_stylesheet_directory() . '/templates/archive-premium.php';
        
        if ( file_exists( $premium_sablon ) ) {
            return $premium_sablon;
        }
    }
    
    // Giriş yapmamış kullanıcılar için kısıtlı görünüm
    if ( ! is_user_logged_in() ) {
        $misafir_sablon = get_stylesheet_directory() . '/templates/archive-misafir.php';
        
        if ( file_exists( $misafir_sablon ) ) {
            return $misafir_sablon;
        }
    }
    
    return $template;
}

Gerçek projede bu tür bir yapı, özellikle LMS (Learning Management System) sitelerinde veya haber portallarında oldukça işe yarar. Aboneler içeriklerin tamamını görebilirken, misafirler sadece başlıkları ve özetleri görebilir.

Senaryo 3: Taxonomy Arşivlerine Dinamik Şablon Atama

Diyelim ki “hizmetler” adında bir taxonomy var ve her terimin kendi benzersiz şablonu olmasını istiyorsunuz. Her terim için ayrı PHP dosyası oluşturmak yerine bunu dinamik hale getirip bir fallback mekanizması kurabilirsiniz:

add_filter( 'template_include', 'hizmetler_taxonomy_sablon_yonlendir' );

function hizmetler_taxonomy_sablon_yonlendir( $template ) {
    if ( ! is_tax( 'hizmetler' ) ) {
        return $template;
    }
    
    $mevcut_terim = get_queried_object();
    
    if ( ! $mevcut_terim ) {
        return $template;
    }
    
    $terim_slug = $mevcut_terim->slug;
    $sablon_klasoru = get_stylesheet_directory() . '/taxonomy-templates/';
    
    // Önce termine özel şablona bak
    $terime_ozel = $sablon_klasoru . 'hizmet-' . $terim_slug . '.php';
    if ( file_exists( $terime_ozel ) ) {
        return $terime_ozel;
    }
    
    // Ebeveyn terim varsa onun şablonuna bak
    if ( $mevcut_terim->parent ) {
        $ebeveyn_terim = get_term( $mevcut_terim->parent, 'hizmetler' );
        $ebeveyn_sablon = $sablon_klasoru . 'hizmet-' . $ebeveyn_terim->slug . '.php';
        
        if ( file_exists( $ebeveyn_sablon ) ) {
            return $ebeveyn_sablon;
        }
    }
    
    // Genel hizmetler arşiv şablonuna düş
    $genel_sablon = $sablon_klasoru . 'hizmetler-genel.php';
    if ( file_exists( $genel_sablon ) ) {
        return $genel_sablon;
    }
    
    return $template;
}

Bu yapı özellikle hiyerarşik taxonomy’lerde çok güçlüdür. Ebeveyn kategorinin şablonu, çocuk kategorilere de uygulanabilir.

Senaryo 4: Sorgu Parametrelerine Göre Şablon Değiştirme

Bazen URL parametrelerine göre farklı bir görünüm sunmak isteyebilirsiniz. Örneğin bir ürün arşivinin liste ve grid görünümü arasında geçiş yapması:

add_filter( 'template_include', 'gorunum_bazli_arsiv_sablonu' );

function gorunum_bazli_arsiv_sablonu( $template ) {
    if ( ! is_post_type_archive( 'urun' ) && ! is_tax( 'urun_kategorisi' ) ) {
        return $template;
    }
    
    $gorunum = isset( $_GET['gorunum'] ) ? sanitize_text_field( $_GET['gorunum'] ) : 'grid';
    
    // Güvenli değerleri beyaz listeye al
    $gecerli_gorunumler = array( 'grid', 'liste', 'kompakt' );
    
    if ( ! in_array( $gorunum, $gecerli_gorunumler ) ) {
        $gorunum = 'grid';
    }
    
    $gorunum_sablonu = get_stylesheet_directory() . '/urun-arsiv/arsiv-' . $gorunum . '.php';
    
    if ( file_exists( $gorunum_sablonu ) ) {
        // Şablon adını body class'a eklemek için oturum veya cookie'ye kaydet
        setcookie( 'arsiv_gorunum', $gorunum, time() + ( 30 * DAY_IN_SECONDS ), '/' );
        return $gorunum_sablonu;
    }
    
    return $template;
}

Burada güvenlik açısından önemli bir nokta var: URL parametresini doğrudan kullanmıyoruz. sanitize_text_field() ile temizliyor ve beyaz liste kontrolü yapıyoruz. Aksi halde path traversal saldırılarına açık kapı bırakmış oluruz.

Senaryo 5: Çocuk Tema ile Ana Tema Şablon Önceliği

Çocuk tema geliştirirken ana temanın arşiv şablonlarını geçersiz kılmak isteyebilirsiniz. WordPress bunu otomatik yapar ancak bazı framework’ler ve page builder’lar bu mekanizmayı bozabilir. İşte güvenli bir çözüm:

add_filter( 'template_include', 'cocuk_tema_arsiv_onceligi', 99 );

function cocuk_tema_arsiv_onceligi( $template ) {
    if ( ! is_archive() ) {
        return $template;
    }
    
    $cocuk_tema_dizini = get_stylesheet_directory();
    $ana_tema_dizini = get_template_directory();
    
    // Zaten çocuk temadan yükleniyorsa dokunma
    if ( strpos( $template, $cocuk_tema_dizini ) !== false ) {
        return $template;
    }
    
    // Ana temadan yüklenen şablonun çocuk tema karşılığını bul
    $goreli_yol = str_replace( $ana_tema_dizini, '', $template );
    $cocuk_tema_sablonu = $cocuk_tema_dizini . $goreli_yol;
    
    if ( file_exists( $cocuk_tema_sablonu ) ) {
        return $cocuk_tema_sablonu;
    }
    
    return $template;
}

Filter priority olarak 99 kullanıyoruz. Bu, diğer plugin’lerin ve WordPress çekirdeğinin işini bitirmesini bekleyip en son müdahale etmemizi sağlar.

Senaryo 6: WooCommerce Kategori Arşivini Özelleştirme

WooCommerce kendi şablon sistemini kullanır ve bazen tema şablonlarıyla çakışabilir. Belirli bir WooCommerce ürün kategorisi için tamamen özel bir şablon kullanmak istediğinizde:

add_filter( 'template_include', 'woo_kategori_ozel_sablon', 100 );

function woo_kategori_ozel_sablon( $template ) {
    if ( ! function_exists( 'is_product_category' ) ) {
        return $template;
    }
    
    if ( ! is_product_category() ) {
        return $template;
    }
    
    $kategori = get_queried_object();
    
    if ( ! $kategori ) {
        return $template;
    }
    
    // Özel meta ile işaretlenmiş kategoriler için özel şablon
    $ozel_sablon_meta = get_term_meta( $kategori->term_id, '_ozel_arsiv_sablon', true );
    
    if ( $ozel_sablon_meta ) {
        $sablon_yolu = get_stylesheet_directory() . '/woo-templates/' . sanitize_file_name( $ozel_sablon_meta ) . '.php';
        
        if ( file_exists( $sablon_yolu ) ) {
            return $sablon_yolu;
        }
    }
    
    // Öne çıkan kategoriler için farklı layout
    $one_cikan = get_term_meta( $kategori->term_id, '_one_cikan_kategori', true );
    
    if ( $one_cikan === 'evet' ) {
        $one_cikan_sablon = get_stylesheet_directory() . '/woo-templates/kategori-one-cikan.php';
        
        if ( file_exists( $one_cikan_sablon ) ) {
            return $one_cikan_sablon;
        }
    }
    
    return $template;
}

WooCommerce filter’ları için priority 100 ve üzeri kullanmanızı öneririm. WooCommerce kendi filter’larını genellikle 10-50 arasında çalıştırır, dolayısıyla 100 ile en son söz sizin olur.

Şablon Yönlendirmede Performans Optimizasyonu

Her sayfa yüklemesinde dosya sistemi kontrolleri yapıyorsunuz. Büyük projelerde bu performans sorununa yol açabilir. Transient API kullanarak bu kontrolleri cache’leyebilirsiniz:

add_filter( 'template_include', 'optimize_arsiv_sablon_yonlendir' );

function optimize_arsiv_sablon_yonlendir( $template ) {
    if ( ! is_archive() ) {
        return $template;
    }
    
    $sorgu_nesne = get_queried_object();
    
    if ( ! $sorgu_nesne ) {
        return $template;
    }
    
    // Cache anahtarı oluştur
    $cache_anahtari = 'arsiv_sablon_' . md5( serialize( array(
        get_class( $sorgu_nesne ),
        isset( $sorgu_nesne->name ) ? $sorgu_nesne->name : '',
        isset( $sorgu_nesne->slug ) ? $sorgu_nesne->slug : ''
    ) ) );
    
    // Cache'den şablonu al
    $cache_sablon = get_transient( $cache_anahtari );
    
    if ( $cache_sablon && file_exists( $cache_sablon ) ) {
        return $cache_sablon;
    }
    
    // Şablon belirleme mantığınız buraya gelir
    $belirlenen_sablon = arsiv_sablon_belirle( $sorgu_nesne, $template );
    
    // 12 saat cache'le
    if ( $belirlenen_sablon !== $template ) {
        set_transient( $cache_anahtari, $belirlenen_sablon, 12 * HOUR_IN_SECONDS );
    }
    
    return $belirlenen_sablon;
}

function arsiv_sablon_belirle( $sorgu_nesne, $varsayilan_sablon ) {
    $sablon_dizini = get_stylesheet_directory() . '/ozel-arsivler/';
    
    if ( isset( $sorgu_nesne->slug ) ) {
        $slug_sablonu = $sablon_dizini . 'arsiv-' . $sorgu_nesne->slug . '.php';
        if ( file_exists( $slug_sablonu ) ) {
            return $slug_sablonu;
        }
    }
    
    return $varsayilan_sablon;
}

Tema güncellemelerinde veya şablon dosyalarını değiştirdiğinizde transient’leri temizlemeyi unutmayın. Bunu switch_theme ve save_post action’larına bağlayabilirsiniz.

Hata Ayıklama Teknikleri

Şablon yönlendirme sorunlarında debug etmek bazen can sıkıcı olabilir. İşte işinize yarayacak birkaç pratik yöntem:

add_filter( 'template_include', 'sablon_debug_log', 999 );

function sablon_debug_log( $template ) {
    // Sadece geliştirme ortamında çalıştır
    if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
        return $template;
    }
    
    // Sadece admin kullanıcılar için görünür yap
    if ( ! current_user_can( 'manage_options' ) ) {
        return $template;
    }
    
    $debug_bilgi = array(
        'yuklenen_sablon'     => $template,
        'is_archive'          => is_archive(),
        'is_tax'              => is_tax(),
        'is_post_type_archive' => is_post_type_archive(),
        'sorgu_tur'           => get_class( get_queried_object() ),
    );
    
    error_log( 'SABLON DEBUG: ' . print_r( $debug_bilgi, true ) );
    
    // HTML olarak da ekle
    add_action( 'wp_footer', function() use ( $template ) {
        echo '<!-- YUKLENEN SABLON: ' . esc_html( $template ) . ' -->';
    } );
    
    return $template;
}

wp-content/debug.log dosyasını izleyerek hangi şablonun yüklendiğini takip edebilirsiniz. wp-config.php içinde WP_DEBUG ve WP_DEBUG_LOG sabitleri açık olmalı.

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

Dosya yolunu yanlış oluşturmak: get_stylesheet_directory() sona / eklemez. Daima manuel olarak ekleyin ya da path_join() fonksiyonunu kullanın.

Priority sırasını göz ardı etmek: Birden fazla plugin aynı filter’ı kullanıyorsa hangisinin önce çalışacağı önemlidir. Kendi kodunuzun en son çalışmasını istiyorsanız yüksek priority (99, 100, 999) kullanın.

Güvenlik kontrollerini atlamak: URL parametrelerinden gelen değerleri asla doğrudan dosya yoluna dahil etmeyin. Her zaman sanitize_file_name() veya beyaz liste kontrolü uygulayın.

Şablon dosyasının varlığını kontrol etmemek: file_exists() kontrolü yapmadan şablon döndürirseniz ve dosya yoksa beyaz ekranla karşılaşırsınız.

template_redirect ile karıştırmak: template_redirect bir action’dır ve HTTP yönlendirmesi için kullanılır. template_include ise bir filter’dır ve dosya yükleme yönlendirmesi içindir. Bu ikisini karıştırmayın.

Sonuç

WordPress’in template_include filter’ı, şablon yönetiminde inanılmaz esneklik sunar. Tema hiyerarşisinin yetersiz kaldığı durumlarda, complex kullanıcı rolleri gerektiren projelerde veya WooCommerce gibi kendi şablon sistemini getiren plugin’lerle çalışırken bu yaklaşım hayat kurtarır.

En önemli kurallar şunlardır:

  • Her zaman file_exists() kontrolü yapın, aksi halde beyaz ekranla karşılaşırsınız
  • Güvenlik önlemlerini asla atlamamayın, kullanıcı girdisini dosya yoluna dahil ederken dikkatli olun
  • Priority değerlerine dikkat edin, plugin çakışmalarını önlemek için uygun öncelik belirleyin
  • Performans için cache kullanın, özellikle yoğun trafik alan sitelerde dosya sistemi kontrollerini minimize edin
  • Debug modunda çalışın, geliştirme sürecinde hangi şablonun yüklendiğini loglamak size çok zaman kazandırır

Bu teknikleri functions.php yerine bir custom plugin içinde kullanmak da iyi bir pratik olur. Tema değişikliklerinden etkilenmeyen, daha taşınabilir bir yapı elde edersiniz. Ama küçük projeler için functions.php içinde kalmak da gayet kabul edilebilir.

Bir yanıt yazın

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