WordPress’te Özel Taxonomy Tanımlama: Kategori ve Etiket Alternatifi

WordPress’in varsayılan kategori ve etiket sistemi çoğu proje için yeterli olsa da, özellikle karmaşık içerik yapıları ve WooCommerce mağazalarında bu yapı yetersiz kalmaya başlıyor. Bir haber sitesi düşün: hem yazı kategorileri hem de yazar uzmanlık alanları hem de içerik türleri var. Bunların hepsini tek bir kategori sistemiyle yönetmeye çalışmak kaosa dönüşüyor. İşte tam bu noktada özel taxonomy kavramı devreye giriyor.

Taxonomy Nedir ve Neden Önemlidir?

WordPress’te taxonomy, içerikleri gruplamak için kullanılan sınıflandırma sistemidir. “Kategori” ve “Etiket” aslında birer taxonomy’dir. Kategori hiyerarşik bir taxonomy iken (üst-alt ilişkisi var), etiket hiyerarşik değildir (düz liste). WordPress bu ikisini varsayılan olarak sunar ama sen kendi taxonomy’lerini tanımlayabilirsin.

Neden özel taxonomy? Çünkü bazı durumlar var ki kategori veya etiketle çözmek hem anlamsız hem de yönetilemez hale geliyor:

  • Bir kitap sitesinde “Yazar”, “Yayınevi”, “Konu” ve “Dönem” gibi birden fazla sınıflandırma boyutuna ihtiyaç duyarsın
  • WooCommerce ürünlerinde ürün kategorisi dışında “Marka”, “Materyal”, “Renk Ailesi” gibi özel filtre alanları gerekir
  • Bir eğitim platformunda “Kurs Seviyesi”, “Sertifika Türü”, “Öğretmen” gibi ayrı taxonomy’ler kullanmak şart

Custom taxonomy tanımlamak için iki yol var: WordPress admin panelinden eklentilerle (Types, Custom Post Type UI gibi) ya da kod yazarak. Biz kod tarafına bakacağız çünkü sysadmin olarak yapıyı gerçekten kontrol altında tutmak istiyoruz.

register_taxonomy() Fonksiyonunu Anlamak

register_taxonomy() fonksiyonu WordPress’in çekirdeğine taxonomy’yi tanıtmak için kullanılır. Temel yapısı şu şekilde:

register_taxonomy(
    string $taxonomy,      // Taxonomy'nin makine adı (slug)
    array|string $object_type, // Hangi post type'lara bağlı
    array $args            // Yapılandırma parametreleri
);

Bu fonksiyonu her zaman init hook’una bağlayarak kullanmalısın. Doğrudan çağırmak yerine hook kullanmak WordPress’in yükleme sırasını doğru yönetmesini sağlar.

İlk Örnek: Basit Bir Hiyerarşik Taxonomy

Bir film veritabanı sitesi yönettiğini düşün. Filmleri türe göre sınıflandırmak istiyorsun ve bu tur yapısı hiyerarşik olacak (Aksiyon > Macera gibi).

function sinema_film_turu_taxonomy() {
    $labels = array(
        'name'              => 'Film Türleri',
        'singular_name'     => 'Film Türü',
        'search_items'      => 'Film Türü Ara',
        'all_items'         => 'Tüm Film Türleri',
        'parent_item'       => 'Üst Tür',
        'parent_item_colon' => 'Üst Tür:',
        'edit_item'         => 'Türü Düzenle',
        'update_item'       => 'Türü Güncelle',
        'add_new_item'      => 'Yeni Tür Ekle',
        'new_item_name'     => 'Yeni Tür Adı',
        'menu_name'         => 'Film Türleri',
    );

    $args = array(
        'hierarchical'      => true,    // Kategori gibi davranır
        'labels'            => $labels,
        'show_ui'           => true,
        'show_admin_column' => true,
        'query_var'         => true,
        'rewrite'           => array( 'slug' => 'film-turu' ),
        'show_in_rest'      => true,    // Gutenberg uyumluluğu için
    );

    register_taxonomy( 'film_turu', array( 'film' ), $args );
}
add_action( 'init', 'sinema_film_turu_taxonomy' );

Burada hierarchical => true ayarı bu taxonomy’yi kategori gibi ağaç yapısına sokar. Admin panelinde checkbox listesi yerine hiyerarşik seçim kutusu göreceksin.

İkinci Örnek: Hiyerarşik Olmayan Taxonomy (Etiket Benzeri)

Aynı film sitesi için yönetmen taxonomy’si ekleyelim. Yönetmenler hiyerarşik olmayacak, düz bir liste:

function sinema_yonetmen_taxonomy() {
    $labels = array(
        'name'                       => 'Yönetmenler',
        'singular_name'              => 'Yönetmen',
        'search_items'               => 'Yönetmen Ara',
        'popular_items'              => 'Popüler Yönetmenler',
        'all_items'                  => 'Tüm Yönetmenler',
        'edit_item'                  => 'Yönetmeni Düzenle',
        'update_item'                => 'Yönetmeni Güncelle',
        'add_new_item'               => 'Yeni Yönetmen Ekle',
        'new_item_name'              => 'Yeni Yönetmen Adı',
        'separate_items_with_commas' => 'Yönetmenleri virgülle ayır',
        'add_or_remove_items'        => 'Yönetmen ekle veya kaldır',
        'choose_from_most_used'      => 'En çok kullanılanlardan seç',
        'menu_name'                  => 'Yönetmenler',
    );

    $args = array(
        'hierarchical'          => false,   // Etiket gibi davranır
        'labels'                => $labels,
        'show_ui'               => true,
        'show_admin_column'     => true,
        'update_count_callback' => '_update_post_term_count',
        'query_var'             => true,
        'rewrite'               => array( 'slug' => 'yonetmen' ),
        'show_in_rest'          => true,
    );

    register_taxonomy( 'yonetmen', 'film', $args );
}
add_action( 'init', 'sinema_yonetmen_taxonomy' );

Hiyerarşik olmayan taxonomy’lerde admin panelinde etiket benzeri bir metin alanı görürsün. Kullanıcılar virgülle ayırarak birden fazla yönetmen ekleyebilir.

WooCommerce Senaryosu: Marka Taxonomy’si

WooCommerce’de ürün taxonomy’si oluşturmak biraz farklı çünkü product post type’ına bağlamamız gerekiyor. Bir e-ticaret mağazası için marka taxonomy’si ekleyelim:

function woo_marka_taxonomy() {
    $labels = array(
        'name'              => 'Markalar',
        'singular_name'     => 'Marka',
        'search_items'      => 'Marka Ara',
        'all_items'         => 'Tüm Markalar',
        'parent_item'       => 'Üst Marka',
        'parent_item_colon' => 'Üst Marka:',
        'edit_item'         => 'Markayı Düzenle',
        'update_item'       => 'Markayı Güncelle',
        'add_new_item'      => 'Yeni Marka Ekle',
        'new_item_name'     => 'Yeni Marka Adı',
        'menu_name'         => 'Markalar',
        'not_found'         => 'Marka bulunamadı',
    );

    $args = array(
        'hierarchical'      => true,
        'labels'            => $labels,
        'show_ui'           => true,
        'show_admin_column' => true,
        'query_var'         => true,
        'rewrite'           => array(
            'slug'         => 'marka',
            'with_front'   => false,  // URL'de /shop/ prefix'i olmadan
            'hierarchical' => true,
        ),
        'show_in_rest'          => true,
        'show_in_nav_menus'     => true,
        'show_tagcloud'         => false,
        'capabilities'          => array(
            'manage_terms' => 'manage_product_terms',
            'edit_terms'   => 'edit_product_terms',
            'delete_terms' => 'delete_product_terms',
            'assign_terms' => 'assign_product_terms',
        ),
    );

    register_taxonomy( 'marka', 'product', $args );
}
add_action( 'init', 'woo_marka_taxonomy' );

capabilities parametresi burada önemli. WooCommerce kendi izin sistemine sahip olduğu için taxonomy yetkilerini de WooCommerce’in kullandığı yetki isimlerine bağlamak mantıklı.

Taxonomy’yi Birden Fazla Post Type’a Bağlamak

Bazen aynı taxonomy’yi hem sayfalarda hem de özel post type’larda kullanmak isteyebilirsin. Örneğin “Proje Kategorisi” hem projeler hem de vaka analizleri için geçerli olabilir:

function genel_proje_kategorisi_taxonomy() {
    $args = array(
        'hierarchical'      => true,
        'label'             => 'Proje Kategorileri',
        'labels'            => array(
            'name'          => 'Proje Kategorileri',
            'singular_name' => 'Proje Kategorisi',
            'add_new_item'  => 'Yeni Kategori Ekle',
            'edit_item'     => 'Kategoriyi Düzenle',
            'menu_name'     => 'Proje Kat.',
        ),
        'show_ui'           => true,
        'show_admin_column' => true,
        'query_var'         => true,
        'rewrite'           => array( 'slug' => 'proje-kategori' ),
        'show_in_rest'      => true,
    );

    // Birden fazla post type'a bağla
    register_taxonomy(
        'proje_kategorisi',
        array( 'proje', 'vaka_analizi', 'referans' ),
        $args
    );
}
add_action( 'init', 'genel_proje_kategorisi_taxonomy' );

Dizi içinde birden fazla post type adı verebilirsin. Bu sayede aynı taxonomy her üç içerik tipinde de görünür.

Sonradan Post Type’a Taxonomy Bağlamak

Bazen taxonomy’yi tanımlarken hangi post type’lara bağlayacağını bilmeyebilirsin, ya da üçüncü parti bir eklentinin post type’ına taxonomy eklemek isteyebilirsin. Bunun için register_taxonomy_for_object_type() kullanırsın:

function woo_urun_markasi_baglantisi() {
    // WooCommerce ürünlerine markayı sonradan bağla
    register_taxonomy_for_object_type( 'marka', 'product' );

    // WooCommerce ürün varyasyonlarına da bağla
    register_taxonomy_for_object_type( 'marka', 'product_variation' );
}
add_action( 'init', 'woo_urun_markasi_baglantisi', 20 ); // Priority 20 ile WooCommerce'den sonra çalış

Priority değerini 20 olarak ayarlamak önemli. WooCommerce init hook’unda kendi post type’larını tanımlıyor. Eğer priority’i 10 bırakırsan WooCommerce henüz product tipini tanımlamamış olabilir.

Taxonomy Terimlerini Programatik Olarak Eklemek

Bazen taxonomy terimlerini kod üzerinden eklemeye ihtiyaç duyarsın. Özellikle tema aktivasyonunda veya migration sırasında bu çok işe yarıyor:

function varsayilan_film_turlerini_ekle() {
    $taxonomy = 'film_turu';

    $varsayilan_turler = array(
        'Aksiyon'  => array( 'slug' => 'aksiyon', 'description' => 'Aksiyon filmleri' ),
        'Komedi'   => array( 'slug' => 'komedi', 'description' => 'Komedi filmleri' ),
        'Dram'     => array( 'slug' => 'dram', 'description' => 'Dram filmleri' ),
        'Bilim Kurgu' => array( 'slug' => 'bilim-kurgu', 'description' => 'Bilim kurgu filmleri' ),
        'Korku'    => array( 'slug' => 'korku', 'description' => 'Korku ve gerilim filmleri' ),
    );

    foreach ( $varsayilan_turler as $tur_adi => $tur_data ) {
        // Term zaten var mı kontrol et
        if ( ! term_exists( $tur_data['slug'], $taxonomy ) ) {
            wp_insert_term(
                $tur_adi,
                $taxonomy,
                array(
                    'slug'        => $tur_data['slug'],
                    'description' => $tur_data['description'],
                )
            );
        }
    }

    // Alt term örneği: Aksiyon > Macera
    $aksiyon_term = get_term_by( 'slug', 'aksiyon', $taxonomy );
    if ( $aksiyon_term && ! term_exists( 'macera', $taxonomy ) ) {
        wp_insert_term(
            'Macera',
            $taxonomy,
            array(
                'slug'   => 'macera',
                'parent' => $aksiyon_term->term_id,
            )
        );
    }
}

// Tema aktif edildiğinde çalıştır
add_action( 'after_switch_theme', 'varsayilan_film_turlerini_ekle' );

term_exists() kontrolü kritik. Aynı kodu her aktifleştirmede çalıştırıyorsan duplicate term oluşmasını engeller.

Özel Taxonomy ile WP_Query Kullanımı

Taxonomy tanımladıktan sonra asıl işi sorgu kısmında yapıyorsun. tax_query parametresi ile çok güçlü filtreler yazabilirsin:

function belirli_turde_filmler_getir( $tur_slug, $limit = 10 ) {
    $args = array(
        'post_type'      => 'film',
        'posts_per_page' => $limit,
        'post_status'    => 'publish',
        'tax_query'      => array(
            'relation' => 'AND',    // Tüm koşullar sağlanmalı
            array(
                'taxonomy' => 'film_turu',
                'field'    => 'slug',
                'terms'    => $tur_slug,
                'operator' => 'IN',  // Bu türde olan filmler
            ),
            array(
                'taxonomy' => 'yonetmen',
                'field'    => 'slug',
                'terms'    => array( 'christopher-nolan', 'quentin-tarantino' ),
                'operator' => 'IN',
            ),
        ),
        'orderby'        => 'date',
        'order'          => 'DESC',
    );

    return new WP_Query( $args );
}

// Kullanımı
$aksiyon_filmler = belirli_turde_filmler_getir( 'aksiyon', 5 );
if ( $aksiyon_filmler->have_posts() ) {
    while ( $aksiyon_filmler->have_posts() ) {
        $aksiyon_filmler->the_post();
        // İçeriği göster
    }
    wp_reset_postdata();
}

operator parametresine dikkat et:

  • IN: Belirtilen terimlerden herhangi biri
  • NOT IN: Belirtilen terimler hariç
  • AND: Tüm belirtilen terimler aynı anda
  • EXISTS: Bu taxonomy’de herhangi bir terimi var
  • NOT EXISTS: Bu taxonomy’de hiçbir terimi yok

Gerçek Dünya Senaryosu: Haber Sitesi Taxonomy Yapısı

Bir haber sitesi kurcalayalım. Kategori yetersiz çünkü hem konu alanı hem de içerik türü hem de coğrafi bölge sınıflandırması gerekiyor:

function haberci_taxonomyleri_tanimla() {

    // 1. Haber Konusu (hiyerarşik)
    register_taxonomy(
        'haber_konusu',
        'post',
        array(
            'hierarchical' => true,
            'label'        => 'Haber Konuları',
            'labels'       => array(
                'name'          => 'Haber Konuları',
                'singular_name' => 'Haber Konusu',
                'add_new_item'  => 'Yeni Konu Ekle',
                'menu_name'     => 'Konular',
            ),
            'show_ui'           => true,
            'show_admin_column' => true,
            'show_in_rest'      => true,
            'query_var'         => true,
            'rewrite'           => array( 'slug' => 'konu' ),
        )
    );

    // 2. İçerik Türü (haber mi, analiz mi, röportaj mı?)
    register_taxonomy(
        'icerik_turu',
        'post',
        array(
            'hierarchical' => false,
            'label'        => 'İçerik Türleri',
            'labels'       => array(
                'name'          => 'İçerik Türleri',
                'singular_name' => 'İçerik Türü',
                'add_new_item'  => 'Yeni Tür Ekle',
                'menu_name'     => 'İçerik Türleri',
            ),
            'show_ui'           => true,
            'show_admin_column' => true,
            'show_in_rest'      => true,
            'query_var'         => true,
            'rewrite'           => array( 'slug' => 'tur' ),
        )
    );

    // 3. Coğrafi Bölge
    register_taxonomy(
        'cografi_bolge',
        array( 'post', 'sayfa' ),
        array(
            'hierarchical' => true,
            'label'        => 'Bölgeler',
            'labels'       => array(
                'name'          => 'Coğrafi Bölgeler',
                'singular_name' => 'Bölge',
                'parent_item'   => 'Üst Bölge',
                'add_new_item'  => 'Yeni Bölge Ekle',
                'menu_name'     => 'Bölgeler',
            ),
            'show_ui'           => true,
            'show_admin_column' => false,  // Admin listede gösterme, çok yer kaplar
            'show_in_rest'      => true,
            'query_var'         => true,
            'rewrite'           => array( 'slug' => 'bolge' ),
        )
    );
}
add_action( 'init', 'haberci_taxonomyleri_tanimla' );

Bu yapıyla bir editör “İstanbul bölgesindeki analiz türündeki ekonomi haberlerini” tek bir query ile çekebilir. Kategori sistemiyle bunu yapmak ya imkansız ya da çok çirkin olurdu.

Taxonomy Sayfası için Özel Template

Taxonomy archive sayfaları için WordPress taxonomy-{taxonomy_adi}.php dosyasını arar. Film türleri için:

// taxonomy-film_turu.php dosyasına ekle

function film_turu_archive_title( $title ) {
    if ( is_tax( 'film_turu' ) ) {
        $term = get_queried_object();
        $film_sayisi = $term->count;
        $title = $term->name . ' Filmleri (' . $film_sayisi . ' film)';
    }
    return $title;
}
add_filter( 'get_the_archive_title', 'film_turu_archive_title' );

// Taxonomy için breadcrumb verisi
function film_turu_breadcrumb() {
    if ( ! is_tax( 'film_turu' ) ) {
        return;
    }

    $term = get_queried_object();
    $breadcrumb = array();

    // Üst termleri bul
    if ( $term->parent ) {
        $ust_term = get_term( $term->parent, 'film_turu' );
        $breadcrumb[] = '<a href="' . get_term_link( $ust_term ) . '">' . $ust_term->name . '</a>';
    }

    $breadcrumb[] = $term->name;

    echo implode( ' &raquo; ', $breadcrumb );
}

Flush Rewrite Rules: En Sık Unutulan Adım

Taxonomy tanımladıktan sonra permalink yapısını güncellemeyi unutma. Bunu ya admin panelinde Ayarlar > Kalıcı Bağlantılar sayfasına girip kaydet yaparak ya da kod üzerinden yapabilirsin:

function taxonomy_aktiflesince_permalink_yenile() {
    sinema_film_turu_taxonomy();
    sinema_yonetmen_taxonomy();
    flush_rewrite_rules();
}
add_action( 'after_switch_theme', 'taxonomy_aktiflesince_permalink_yenile' );

// Geliştirme ortamında manuel tetikleme için
// wp-cli kullanıyorsan:
// wp rewrite flush

Dikkat: flush_rewrite_rules() her sayfa yüklemesinde çalıştırma. Bu fonksiyon veritabanı yazma işlemi yapıyor ve performansı ciddi etkiliyor. Sadece tema veya eklenti aktifleştirme hookuna bağla.

Taxonomy Yetki Yönetimi

Sadece belirli rollerin taxonomy yönetebilmesini isteyebilirsin. Özellikle çok yazarlı sitelerde bu kritik:

function taxonomy_yetki_ayarla() {
    // Editor rolüne film türü yönetme yetkisi ver
    $editor = get_role( 'editor' );
    if ( $editor ) {
        $editor->add_cap( 'manage_film_terms' );
        $editor->add_cap( 'edit_film_terms' );
        $editor->add_cap( 'delete_film_terms' );
        $editor->add_cap( 'assign_film_terms' );
    }

    // Yazar rolüne sadece atama yetkisi ver (ekleme/silme yok)
    $yazar = get_role( 'author' );
    if ( $yazar ) {
        $yazar->add_cap( 'assign_film_terms' );
        // manage ve delete yetkisi verme
    }
}
add_action( 'admin_init', 'taxonomy_yetki_ayarla' );

// Taxonomy tanımında capabilities belirt
function film_turu_taxonomy_yetkili() {
    register_taxonomy(
        'film_turu_ozel',
        'film',
        array(
            'hierarchical' => true,
            'label'        => 'Film Türleri',
            'show_ui'      => true,
            'capabilities' => array(
                'manage_terms' => 'manage_film_terms',
                'edit_terms'   => 'edit_film_terms',
                'delete_terms' => 'delete_film_terms',
                'assign_terms' => 'assign_film_terms',
            ),
        )
    );
}
add_action( 'init', 'film_turu_taxonomy_yetkili' );

Sık Yapılan Hatalar

Taxonomy çalışırken bazı tuzaklarla karşılaşırsın:

  • Taxonomy adı çok uzun: Taxonomy makine adı 32 karakteri geçmemeli. film_kategorisi_ana_grup gibi uzun isimler sorun çıkarabilir.
  • Reserved isimler kullanmak: category, post_tag, nav_menu, link_category, post_format gibi WordPress’in rezerve ettiği isimleri kullanma.
  • flush_rewrite_rules her yerde: Dediğim gibi bunu sadece aktivasyon hookunda çalıştır. Her init‘te çalıştırırsan sitenin performansı çöker.
  • show_in_rest unutmak: Gutenberg editörünü kullanıyorsan bu parametre olmadan taxonomy blok editöründe görünmez.
  • WooCommerce taxonomy’lerine çakışmak: product_cat, product_tag, product_shipping_class isimlerini kullanma.

Sonuç

Özel taxonomy sistemi WordPress’in en güçlü ama en az kullanılan özelliklerinden biri. Doğru tasarlandığında içerik mimarini tamamen dönüştürüyor. Kategori ve etiketle çözemeyeceğin karmaşık sınıflandırma ihtiyaçlarında taxonomy’ler hem yöneticinin işini kolaylaştırıyor hem de sorgu performansını artırıyor.

Sonuç olarak şunu söyleyebilirim: Bir proje başlangıcında “bu içerikler nasıl gruplandırılacak?” sorusunu sormak ve buna göre taxonomy yapısını tasarlamak, ileride onlarca kategori içinde boğulmaktan seni kurtarır. WooCommerce projelerinde marka, materyal, renk ailesi gibi taxonomy’leri baştan kurmak, ürün filtreleme sistemini kurarken hayatını çok kolaylaştırır. Taxonomy’leri bir kez doğru tasarla, uzun yıllar sorunsuz çalışır.

Bir yanıt yazın

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