WordPress Ana Sayfa ve Kategori Sorgu Parametrelerini Değiştirme

WordPress sitenizin performansını ve kullanıcı deneyimini ince ayarlamak istediğinizde, sorgu parametrelerini kontrol etmek son derece güçlü bir araç haline gelir. Özellikle ana sayfa ve kategori sayfalarında WordPress’in varsayılan sorgu davranışını değiştirmek, hem SEO hem de kullanıcı deneyimi açısından ciddi farklar yaratabilir. Bu yazıda functions.php dosyasını kullanarak bu sorguları nasıl manipüle edebileceğinizi, gerçek dünya senaryolarıyla birlikte ele alacağız.

WordPress Sorgu Sistemi Nasıl Çalışır?

WordPress her sayfa yüklendiğinde arka planda bir WP_Query nesnesi oluşturur. Bu nesne, hangi içeriklerin gösterileceğini, hangi kategorilerden çekileceğini, kaç gönderi listeleneceğini ve sıralama kriterlerini belirler. Bu sorguya ana sorgu (main query) diyoruz.

pre_get_posts kancası, bu ana sorgu veritabanına gitmeden hemen önce devreye girerek sorgu parametrelerini değiştirmenize olanak tanır. Bu, yeni bir sorgu oluşturmaktan çok daha verimli bir yaklaşımdır çünkü ek bir veritabanı yükü oluşturmaz.

Ana sorguyu değiştirmek için iki temel kontrol yapmanız şarttır:

  • is_admin() kontrolü: Yönetici panelindeki sorguları etkilememek için
  • is_main_query() kontrolü: Yalnızca ana sorguyu değiştirdiğinizden emin olmak için

Bu iki kontrolü atladığınızda hem admin paneli bozulur hem de widgetlar veya özel sorgular istemediğiniz şekilde etkilenir.

Temel pre_get_posts Kullanımı

En basit haliyle pre_get_posts kancasını şöyle kullanırsınız:

<?php
function custom_modify_main_query( $query ) {
    if ( ! is_admin() && $query->is_main_query() ) {
        // Sorgu değişiklikleriniz buraya
    }
}
add_action( 'pre_get_posts', 'custom_modify_main_query' );

Bu yapı, tüm sorgu değişikliklerinizin çıkış noktası olacak. Şimdi gerçek dünya senaryolarına geçelim.

Ana Sayfada Gönderi Sayısını Değiştirme

Diyelim ki bir haber portalı yönetiyorsunuz. Ana sayfada varsayılan olarak WordPress’in ayarlardan belirlediği sayıda gönderi gösteriliyor ancak siz ana sayfada 12 gönderi, kategori sayfalarında ise 9 gönderi göstermek istiyorsunuz.

<?php
function custom_posts_per_page( $query ) {
    if ( ! is_admin() && $query->is_main_query() ) {
        if ( $query->is_home() ) {
            $query->set( 'posts_per_page', 12 );
        }
        if ( $query->is_category() ) {
            $query->set( 'posts_per_page', 9 );
        }
    }
}
add_action( 'pre_get_posts', 'custom_posts_per_page' );

Buradaki is_home() kontrolü, WordPress’te statik bir sayfa ön sayfası olarak ayarlanmamışsa ana blog akışını temsil eder. Eğer ayarlardan “Ön Sayfanı Görüntüle” kısmında “En son gönderileriniz” seçiliyse bu çalışır. Statik ön sayfa kullanıyorsanız is_front_page() kullanmanız gerekir.

Kategori Sayfalarında Özel Sıralama

Bir e-ticaret sitesi işletiyorsunuz ve kategori sayfalarınızda ürün gönderilerini tarih yerine başlığa göre alfabetik sıralamak istiyorsunuz. Ya da belki popüler gönderileri önce göstermek istiyorsunuz.

<?php
function custom_category_orderby( $query ) {
    if ( ! is_admin() && $query->is_main_query() ) {
        if ( $query->is_category() ) {
            // Alfabetik sıralama
            $query->set( 'orderby', 'title' );
            $query->set( 'order', 'ASC' );
        }
        if ( $query->is_tag() ) {
            // Etiket sayfalarında yorum sayısına göre sırala
            $query->set( 'orderby', 'comment_count' );
            $query->set( 'order', 'DESC' );
        }
    }
}
add_action( 'pre_get_posts', 'custom_category_orderby' );

orderby parametresi için kullanabileceğiniz değerler oldukça geniş:

  • date: Yayın tarihine göre (varsayılan)
  • title: Başlığa göre alfabetik
  • modified: Son düzenleme tarihine göre
  • comment_count: Yorum sayısına göre
  • rand: Rastgele sıralama
  • menu_order: Menü sıralamasına göre
  • meta_value: Özel alan değerine göre
  • meta_value_num: Sayısal özel alan değerine göre

Belirli Kategorileri Ana Sayfadan Hariç Tutma

Gerçek bir senaryo: Bir müşterinin sitesinde “Duyurular” adında bir kategoriniz var ve bu kategori sadece iç iletişim için kullanılıyor. Bu kategorinin gönderilerini ana sayfada göstermek istemiyorsunuz.

<?php
function exclude_categories_from_homepage( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
        // Hariç tutulacak kategori ID'leri
        // Negatif değer = hariç tut
        $excluded_cats = array( -5, -12, -23 );
        $query->set( 'cat', implode( ',', $excluded_cats ) );
    }
}
add_action( 'pre_get_posts', 'exclude_categories_from_homepage' );

Alternatif olarak category__not_in parametresini de kullanabilirsiniz, bu daha okunabilir bir yaklaşımdır:

<?php
function exclude_categories_cleaner( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
        $excluded = array( 5, 12, 23 ); // Kategori ID'leri
        $query->set( 'category__not_in', $excluded );
    }
}
add_action( 'pre_get_posts', 'exclude_categories_cleaner' );

Kategori ID’sini bulmak için WordPress admin panelinde “Yazılar > Kategoriler” bölümüne gidin, ilgili kategorinin üzerine gelin ve URL’deki tag_ID parametresine bakın.

Birden Fazla Post Type Gösterme

WordPress’in varsayılan davranışı ana sayfada sadece post tipindeki içerikleri göstermektir. Diyelim ki bir portfolyo sitesi yönetiyorsunuz ve hem blog yazılarını hem de portfolyo projelerini aynı akışta göstermek istiyorsunuz.

<?php
function show_multiple_post_types( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
        $query->set( 'post_type', array( 'post', 'portfolio', 'case_study' ) );
    }
}
add_action( 'pre_get_posts', 'show_multiple_post_types' );

Bu yaklaşım özellikle ajans sitelerinde veya çok içerik tipli platformlarda çok işe yarıyor. Ancak dikkat edin: farklı post type’lar için şablonunuzun bu içerikleri düzgün gösterebilmesi gerekiyor.

Yazar Bazlı Filtreleme ve Özel Meta Sorguları

Diyelim ki bir çok yazarlı blog yönetiyorsunuz. Belirli bir kategoride sadece editör statüsündeki kullanıcıların yazılarını göstermek istiyorsunuz. Bunun için meta sorguları ile birleştirilmiş bir yaklaşım kullanabilirsiniz:

<?php
function filter_by_author_role_in_category( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_category( 'haberler' ) ) {
        
        // Editör rolündeki kullanıcıları bul
        $editor_users = get_users( array(
            'role'   => 'editor',
            'fields' => 'ID',
        ) );
        
        if ( ! empty( $editor_users ) ) {
            $query->set( 'author__in', $editor_users );
        }
    }
}
add_action( 'pre_get_posts', 'filter_by_author_role_in_category' );

Bu fonksiyon “haberler” slug’una sahip kategori sayfasında sadece editörlerin yazılarını gösterir. is_category() fonksiyonuna kategori ID’si, slug veya isim verebilirsiniz.

Meta Query ile Özel Alan Filtrelemesi

WooCommerce kullanan bir sitede veya özel alanlar içeren bir içerik yönetim sisteminde, belirli meta değerlere göre filtreleme yapmak sıkça ihtiyaç duyulan bir senaryodur:

<?php
function filter_featured_posts_on_homepage( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
        
        $meta_query = array(
            'relation' => 'OR',
            array(
                'key'     => 'featured_post',
                'value'   => '1',
                'compare' => '=',
            ),
            array(
                'key'     => 'editor_pick',
                'value'   => 'yes',
                'compare' => '=',
            ),
        );
        
        $query->set( 'meta_query', $meta_query );
        $query->set( 'posts_per_page', 6 );
        $query->set( 'orderby', array(
            'date' => 'DESC',
        ) );
    }
}
add_action( 'pre_get_posts', 'filter_featured_posts_on_homepage' );

Bu örnekte relation => OR kullanarak iki farklı koşuldan birini karşılayan gönderileri getiriyoruz. AND kullanırsanız her iki koşulu da karşılaması gerekir.

Tarih Bazlı Filtreleme

Bazen eski içerikleri listelerden hariç tutmak istersiniz. Özellikle etkinlik sitelerinde veya zaman bazlı içerik yönetiminde bu çok işe yarar:

<?php
function exclude_old_posts_from_category( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_category() ) {
        
        // Son 1 yılın gönderilerini göster
        $query->set( 'date_query', array(
            array(
                'after'     => '1 year ago',
                'inclusive' => true,
            ),
        ) );
        
        // Ya da belirli tarih aralığı:
        // $query->set( 'date_query', array(
        //     array(
        //         'after'  => array(
        //             'year'  => 2023,
        //             'month' => 1,
        //             'day'   => 1,
        //         ),
        //         'before' => array(
        //             'year'  => 2024,
        //             'month' => 12,
        //             'day'   => 31,
        //         ),
        //         'inclusive' => true,
        //     ),
        // ) );
    }
}
add_action( 'pre_get_posts', 'exclude_old_posts_from_category' );

Taxonomy Sorguları ile Gelişmiş Filtreleme

Özel taksonomiler kullanıyorsanız, tax_query parametresi inanılmaz derecede esnek filtreleme imkanı sunar:

<?php
function filter_by_custom_taxonomy( $query ) {
    if ( ! is_admin() && $query->is_main_query() ) {
        
        // Ana sayfada sadece "premium" etiketli içerikleri göster
        if ( $query->is_home() ) {
            $query->set( 'tax_query', array(
                array(
                    'taxonomy' => 'icerik-turu',
                    'field'    => 'slug',
                    'terms'    => array( 'premium', 'ozel' ),
                    'operator' => 'IN',
                ),
            ) );
        }
        
        // Belirli bir özel kategoride "sponsor" içerikleri hariç tut
        if ( $query->is_category( 'teknoloji' ) ) {
            $query->set( 'tax_query', array(
                array(
                    'taxonomy' => 'icerik-turu',
                    'field'    => 'slug',
                    'terms'    => array( 'sponsor' ),
                    'operator' => 'NOT IN',
                ),
            ) );
        }
    }
}
add_action( 'pre_get_posts', 'filter_by_custom_taxonomy' );

operator parametresi için kullanabileceğiniz değerler:

  • IN: Belirtilen terimlerden herhangi birini içerenler
  • NOT IN: Belirtilen terimlerin hiçbirini içermeyenler
  • AND: Belirtilen terimlerin tamamını içerenler
  • EXISTS: O taksonomi için herhangi bir terimi olanlar
  • NOT EXISTS: O taksonomi için hiç terimi olmayanlar

Arama Sonuçlarını İyileştirme

WordPress’in varsayılan arama fonksiyonu oldukça kısıtlıdır. Sadece başlık ve içeriği tarar, özel alanları dahil etmez. Bunu da pre_get_posts ile iyileştirebilirsiniz:

<?php
function improve_search_query( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_search() ) {
        
        // Arama sonuçlarında birden fazla post type göster
        $query->set( 'post_type', array( 'post', 'page', 'portfolio' ) );
        
        // Sayfalama için sonuç sayısını ayarla
        $query->set( 'posts_per_page', 15 );
        
        // Sadece yayınlanmış içerikleri göster (normalde varsayılan ama garantilemek için)
        $query->set( 'post_status', 'publish' );
        
        // Belirli kategorileri arama dışında bırak
        $query->set( 'category__not_in', array( 99 ) ); // Gizli kategori
    }
}
add_action( 'pre_get_posts', 'improve_search_query' );

Tüm Değişiklikleri Bir Fonksiyonda Toplamak

Gerçek dünya projelerinde bu değişikliklerin hepsini ayrı ayrı fonksiyonlarda tutmak yerine, tek ve organize bir fonksiyon içinde yönetmek çok daha iyi bir pratiktir:

<?php
function sitewide_query_modifications( $query ) {
    
    // Güvenlik kontrolü - her zaman ilk iki koşul
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    
    /**
     * Ana Sayfa Sorgu Ayarları
     */
    if ( $query->is_home() ) {
        $query->set( 'posts_per_page', 12 );
        $query->set( 'category__not_in', array( 5, 23 ) );
        $query->set( 'post_type', array( 'post', 'portfolio' ) );
        return; // Diğer koşulların çalışmasını engelle
    }
    
    /**
     * Kategori Sayfası Sorgu Ayarları
     */
    if ( $query->is_category() ) {
        $query->set( 'posts_per_page', 9 );
        $query->set( 'orderby', 'date' );
        $query->set( 'order', 'DESC' );
        
        // "Teknoloji" kategorisinde özel sıralama
        if ( $query->is_category( 'teknoloji' ) ) {
            $query->set( 'orderby', 'comment_count' );
        }
        return;
    }
    
    /**
     * Etiket Sayfası Sorgu Ayarları
     */
    if ( $query->is_tag() ) {
        $query->set( 'posts_per_page', 15 );
        return;
    }
    
    /**
     * Arama Sorgu Ayarları
     */
    if ( $query->is_search() ) {
        $query->set( 'posts_per_page', 20 );
        $query->set( 'post_type', array( 'post', 'page' ) );
        return;
    }
    
    /**
     * Yazar Sayfası Sorgu Ayarları
     */
    if ( $query->is_author() ) {
        $query->set( 'posts_per_page', 10 );
        $query->set( 'orderby', 'date' );
        $query->set( 'order', 'DESC' );
        return;
    }
}
add_action( 'pre_get_posts', 'sitewide_query_modifications' );

Bu yaklaşımda her koşulun sonunda return kullanarak gereksiz kontrollerin yapılmasını engelliyoruz ve kodu daha okunabilir hale getiriyoruz.

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

pre_get_posts kullanırken karşılaşılan en yaygın sorunlar:

  • is_admin() kontrolünü atlamak: Admin panelinde beklenmedik davranışlara yol açar, ürün listeleme bozulabilir
  • is_main_query() kontrolünü atlamak: Widget sorguları, ilgili yazı sorguları etkilenir
  • Statik ön sayfa ile is_home() karışıklığı: Statik ön sayfa kullanıyorsanız is_home() çalışmaz, is_front_page() kullanın
  • posts_per_page yerine showposts kullanmak: showposts eski bir parametre, artık posts_per_page kullanın
  • Çok fazla meta_query birleştirmek: Her ek meta sorgusu veritabanı yükünü artırır, dikkatli kullanın

Performans İpuçları

Sorgu değişikliklerinizi yaparken performansı göz önünde bulundurmanız şart:

  • Sadece ihtiyaç duyduğunuz alanları getirin: fields parametresiyle sadece ID veya ID ve title getirebilirsiniz
  • no_found_rows parametresini kullanın: Sayfalama kullanmıyorsanız $query->set('no_found_rows', true) ekleyin, bu FOUND_ROWS() sorgusunu atlar
  • Meta sorgularını indexleyin: Sık kullandığınız meta key’ler için veritabanı indexi oluşturun
  • Sorgu önbelleğini kullanın: Object cache ile birleştirdiğinizde sorgu değişiklikleri çok daha hızlı çalışır

Sonuç

pre_get_posts kancası, WordPress’in en güçlü araçlarından biridir. Ana sayfa ve kategori sayfalarındaki sorgu parametrelerini bu şekilde kontrol etmek, yeni WP_Query nesneleri oluşturmaktan çok daha verimli ve WordPress’in doğal akışıyla uyumludur.

Önemli noktaları özetlersek: Her zaman is_admin() ve is_main_query() kontrollerini yapın, değişikliklerinizi tek ve organize bir fonksiyonda toplayın, performans etkilerini göz önünde bulundurun ve değişikliklerinizi staging ortamında test ettikten sonra canlıya alın.

Bu yaklaşımla site davranışını eklenti kullanmadan, tema bağımsız bir şekilde ve çok daha az kaynak kullanarak kontrol altına alabilirsiniz. functions.php dosyasını bir kara kutu olarak değil, sitenizin davranış merkezi olarak düşündüğünüzde WordPress’in gerçek potansiyelini keşfetmeye başlarsınız.

Bir yanıt yazın

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