WordPress Action ve Filter Hook Farkı: Temel Kavramlar

WordPress ile ciddi anlamda uğraşmaya başladığında er ya da geç add_action ve add_filter fonksiyonlarıyla karşılaşırsın. İlk bakışta ikisi de benzer görünür, ikisi de bir şeyleri “hook eder”, ikisi de functions.php dosyasına yazılır. Ama aralarındaki fark, WordPress’in kalp atışını anlamak için kritik öneme sahip. Yanlış hook türünü kullandığında ya hiçbir şey olmaz, ya da saatlerce debug yaparsın. Bu yazıda action ve filter hook’larının ne olduğunu, nasıl çalıştığını ve gerçek dünya senaryolarında nasıl kullanacağını somut kod örnekleriyle açıklıyorum.

WordPress Hook Sistemi Nedir

WordPress, event-driven (olay güdümlü) bir mimariye sahiptir. Yani WordPress çalışırken belirli noktalarda “şu an buraya geldim, biri bir şey yapmak istiyor mu?” diye sorar. Bu noktalara hook denir.

Hook sistemi iki temel bileşenden oluşur:

  • Action Hook: Bir şey olduğunda tetiklenir, genellikle bir işlem yapman için kullanılır
  • Filter Hook: Bir veri geçerken onu değiştirmene izin verir, veriyi geri döndürmen gerekir

Bunu şöyle düşün: Action hook bir alarm gibidir, “kaydet butonu tıklandı, ne yapmak istiyorsan yap” der. Filter hook ise bir boru hattındaki valf gibidir, içinden geçen veriyi alır, değiştirirsin, tekrar bırakırsın.

Action Hook: İşlem Tetikleyiciler

Action hook’lar, WordPress’in belirli bir noktaya ulaştığında senin fonksiyonunu çalıştırmasını sağlar. Herhangi bir değer döndürmene gerek yoktur, sadece bir şey yaparsın ve işin biter.

add_action Söz Dizimi

add_action( string $hook_name, callable $callback, int $priority = 10, int $accepted_args = 1 )

Parametreler şöyle:

  • $hook_name: Bağlanmak istediğin action hook’un adı (örneğin wp_head, save_post, init)
  • $callback: Tetiklenecek fonksiyon adı
  • $priority: Öncelik sırası, düşük sayı önce çalışır, varsayılan 10
  • $accepted_args: Callback fonksiyonunun kaç parametre alacağı

Basit Action Hook Örneği

Sayfanın bölümüne özel bir meta etiketi eklemek istediğini düşün:

function custom_meta_viewport() {
    echo '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
}
add_action( 'wp_head', 'custom_meta_viewport' );

Bu kod wp_head action’ı tetiklendiğinde, yani WordPress etiketlerini yazdırırken, senin fonksiyonunu da çalıştırır. Geri dönüş değeri yok, sadece bir şey “yapıyorsun”.

Gerçek Dünya: Yeni Kullanıcı Kaydında E-posta Bildirimi

Bir müşteri sitesinde yeni kullanıcı kaydolduğunda site adminine bildirim gitmesini istiyorsun ama WordPress’in varsayılan e-postasını değiştirmeden ek bir bildirim eklemek istiyorsun:

function notify_admin_new_user( $user_id ) {
    $user_info = get_userdata( $user_id );
    $admin_email = get_option( 'admin_email' );
    
    $subject = 'Yeni Kullanıcı Kaydı: ' . $user_info->user_login;
    $message = 'Yeni bir kullanıcı kayıt oldu.' . "nn";
    $message .= 'Kullanıcı adı: ' . $user_info->user_login . "n";
    $message .= 'E-posta: ' . $user_info->user_email . "n";
    $message .= 'Kayıt tarihi: ' . current_time( 'mysql' );
    
    wp_mail( $admin_email, $subject, $message );
}
add_action( 'user_register', 'notify_admin_new_user', 10, 1 );

Burada user_register action’ı $user_id parametresini bize iletir, biz de bunu kullanarak kullanıcı bilgilerini çekiyoruz. accepted_args parametresini 1 olarak verdik çünkü sadece bir argüman alıyoruz.

Gerçek Dünya: Post Kaydedildiğinde Cache Temizleme

Bir sunucuda Redis veya Memcached kullanıyorsun ve bir post güncellendiğinde ilgili cache anahtarını temizlemen gerekiyor:

function clear_post_cache_on_save( $post_id, $post, $update ) {
    // Otomatik kaydetme ve revizyon kontrolü
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }
    
    if ( wp_is_post_revision( $post_id ) ) {
        return;
    }
    
    // Sadece yayınlanmış post'lar için
    if ( $post->post_status !== 'publish' ) {
        return;
    }
    
    $cache_key = 'post_data_' . $post_id;
    
    // WordPress object cache'den sil
    wp_cache_delete( $cache_key, 'posts' );
    
    // Özel log yaz
    error_log( 'Cache temizlendi: ' . $cache_key . ' - ' . current_time( 'mysql' ) );
}
add_action( 'save_post', 'clear_post_cache_on_save', 10, 3 );

Burada accepted_args parametresini 3 yaptık çünkü save_post hook’u $post_id, $post, $update olmak üzere üç parametre geçirir.

Filter Hook: Veri Dönüştürücüler

Filter hook’lar, bir veri bir yerden bir yere giderken o veriyi yakalayıp değiştirmeni sağlar. Buradaki kritik kural şudur: filter callback’in her zaman bir değer return etmesi gerekir. Return etmeyi unutursan veri kaybolur ve site büyük ihtimalle bozulur.

add_filter Söz Dizimi

add_filter( string $hook_name, callable $callback, int $priority = 10, int $accepted_args = 1 )

Söz dizimi action ile aynıdır ama çalışma mantığı farklıdır. Filter callback mutlaka değer döndürmelidir.

Basit Filter Hook Örneği

WordPress’in ürettiği excerpt (özet) uzunluğunu değiştirmek istiyorsun:

function custom_excerpt_length( $length ) {
    return 30;
}
add_filter( 'excerpt_length', 'custom_excerpt_length' );

$length değişkeni WordPress’in varsayılan değerini (55 kelime) taşır. Biz bunu alıp 30 döndürüyoruz. WordPress bu dönen değeri kullanır.

Gerçek Dünya: Başlıklara Otomatik SEO Ek Metni

Her sayfa başlığının sonuna site adını eklemek istiyorsun, ama bunu tema koduna dokunmadan yapmak istiyorsun:

function append_site_name_to_title( $title ) {
    if ( is_home() || is_front_page() ) {
        return $title;
    }
    
    $site_name = get_bloginfo( 'name' );
    
    // Başlık zaten site adını içeriyorsa tekrarlama
    if ( strpos( $title, $site_name ) !== false ) {
        return $title;
    }
    
    return $title . ' | ' . $site_name;
}
add_filter( 'the_title', 'append_site_name_to_title' );

Gerçek Dünya: WooCommerce Ürün Fiyatlarına Vergi Bilgisi Ekleme

WooCommerce kullanıyorsun ve her fiyatın yanına “KDV Dahil” metnini eklemek istiyorsun:

function add_tax_notice_to_price( $price, $product ) {
    // Admin panelinde gösterme
    if ( is_admin() ) {
        return $price;
    }
    
    // Sadece sepette değil, ürün sayfalarında göster
    if ( is_product() || is_shop() || is_product_category() ) {
        $price = $price . ' <small class="tax-notice">(KDV Dahil)</small>';
    }
    
    return $price;
}
add_filter( 'woocommerce_get_price_html', 'add_tax_notice_to_price', 10, 2 );

Dikkat et: accepted_args değerini 2 yaptık çünkü woocommerce_get_price_html filter’ı hem $price hem de $product nesnesini geçiriyor. İkinci argümanı kullanmasak bile, geçirildiğini belirtmemiz gerekiyor.

Action ve Filter Arasındaki Temel Farklar

İki hook türünü karıştırmamak için şu prensipleri kafana kazı:

  • Action hook’lar: Bir şey “olur”, sen de bu olaya tepki verirsin. Return değeri önemsizdir
  • Filter hook’lar: Bir veri “geçer”, sen de bu veriyi değiştirip geri verirsin. Return zorunludur
  • Action’da do_action() fonksiyonu kullanılır, filter’da apply_filters() kullanılır
  • Action’da hiçbir şey return etmesen de dünya dönmeye devam eder
  • Filter’da return etmezsen null döner ve veri yok olur

Filter’da Return Unutmanın Felaket Senaryosu

// YANLIS - Return yok!
function bad_filter_example( $content ) {
    $content = str_replace( 'foo', 'bar', $content );
    // return yok! Tüm post içeriği silindi!
}
add_filter( 'the_content', 'bad_filter_example' );

// DOGRU
function good_filter_example( $content ) {
    $content = str_replace( 'foo', 'bar', $content );
    return $content; // Her zaman return et!
}
add_filter( 'the_content', 'good_filter_example' );

Bu hata production ortamında yapıldığında tüm yazı içerikleri boş görünür. Bunu yaşayan sysadmin sayısı tahmin ettiğinden fazladır.

Priority (Öncelik) Mantığı

Aynı hook’a birden fazla fonksiyon bağlanabilir. Priority değeri hangi fonksiyonun önce çalışacağını belirler.

// Önce çalışır (priority 5)
add_filter( 'the_content', 'ilk_degisiklik', 5 );

// Sonra çalışır (priority 10, varsayılan)
add_filter( 'the_content', 'ikinci_degisiklik', 10 );

// En son çalışır (priority 20)
add_filter( 'the_content', 'ucuncu_degisiklik', 20 );

Gerçek Dünya: Tema ve Plugin Çakışması Çözümü

Bir tema wp_footer action’ına priority 10 ile bir script ekliyor, ama senin jQuery bağımlı scriptin ondan önce yükleniyor ve çakışıyor. Çözüm:

// Tema'nın scriptini kaldır
function remove_theme_footer_script() {
    remove_action( 'wp_footer', 'tema_footer_script_fonksiyonu', 10 );
}
add_action( 'wp_footer', 'remove_theme_footer_script', 9 );

// Kendi scriptini daha sonra ekle
function add_custom_footer_script() {
    echo '<script>console.log("Script hazır");</script>';
}
add_action( 'wp_footer', 'add_custom_footer_script', 99 );

Kendi Hook’larını Tanımlamak

Sadece WordPress core’un hook’larını kullanmakla sınırlı değilsin. Kendi hook’larını oluşturabilirsin. Bu özellikle plugin geliştirirken veya tema özelleştirilebilirliği sağlarken çok işe yarar.

Özel Action Hook Tanımlama

// Bir işlem gerçekleştiğinde özel action tetikle
function process_custom_form( $form_data ) {
    // Form verilerini işle
    $processed_data = sanitize_form_data( $form_data );
    
    // Diğer pluginlerin veya kodların bu noktada devreye girmesine izin ver
    do_action( 'my_plugin_form_processed', $processed_data );
    
    // Veriyi kaydet
    save_form_to_database( $processed_data );
}

// Başka bir dosyada ya da functions.php'de bu hook'a bağlan
function log_form_submission( $data ) {
    error_log( 'Form gönderildi: ' . json_encode( $data ) );
}
add_action( 'my_plugin_form_processed', 'log_form_submission' );

Özel Filter Hook Tanımlama

// Kendi filter hook'unu oluştur
function get_custom_greeting( $user_name ) {
    $greeting = 'Merhaba, ' . $user_name . '!';
    
    // Diğerlerinin bu mesajı değiştirmesine izin ver
    $greeting = apply_filters( 'my_plugin_greeting_message', $greeting, $user_name );
    
    return $greeting;
}

// Başka bir yerde bu filter'a bağlan
function change_greeting_for_admins( $greeting, $user_name ) {
    if ( current_user_can( 'administrator' ) ) {
        $greeting = 'Hoşgeldiniz, Sayın ' . $user_name . ' (Admin)';
    }
    return $greeting;
}
add_filter( 'my_plugin_greeting_message', 'change_greeting_for_admins', 10, 2 );

Hook’ları Kaldırmak: remove_action ve remove_filter

Eklediğin hook’ları kaldırabildiğin gibi, başkalarının eklediği hook’ları da kaldırabilirsin. Bu özellikle şişirilmiş tema fonksiyonlarını devre dışı bırakmak için sıkça kullanılır.

// Woocommerce'in varsayılan "ilgili ürünler" bölümünü kaldır
remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );

// Yerine kendi versiyonunu ekle
function custom_related_products() {
    // Özelleştirilmiş ilgili ürünler burada
    woocommerce_related_products( array(
        'posts_per_page' => 3,
        'columns'        => 3,
        'orderby'        => 'rand'
    ) );
}
add_action( 'woocommerce_after_single_product_summary', 'custom_related_products', 20 );

Dikkat: remove_action ve remove_filter kullanırken, kaldırmak istediğin hook’un önce yüklenmiş olması gerekir. Yanlış sıralama yaparsanız kaldırma işlemi çalışmaz.

Sık Yapılan Hatalar ve Debug İpuçları

Sysadmin olarak hangi hook’un ne zaman tetiklendiğini takip etmek can sıkıcı olabilir. İşte birkaç pratik yaklaşım:

// Hangi hook'un çalıştığını logla (geliştirme ortamında)
function debug_current_hook() {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        $current_hook = current_filter(); // Hem action hem filter için çalışır
        error_log( 'Aktif hook: ' . $current_hook );
    }
}
// Birden fazla hook'a bağla
add_action( 'init', 'debug_current_hook' );
add_action( 'wp_loaded', 'debug_current_hook' );
add_action( 'template_redirect', 'debug_current_hook' );

Yaygın hatalar şunlar:

  • Filter’da return etmemek: İçerik kaybına neden olur, en tehlikeli hata
  • Yanlış priority sırası: Hook çalışıyor ama beklenen etki görülmüyor
  • accepted_args eksik belirtmek: Fazla argüman alan hook’larda fonksiyon doğru çalışmaz
  • Global scope yerine hook içinde fonksiyon çağırmak: Bazı WordPress fonksiyonları erken çağrıldığında çalışmaz
  • Sonsuz döngü: Filter içinde aynı filter’ı tetikleyen bir işlem yapmak

Sonuç

WordPress hook sistemi, temaya veya plugin koduna dokunmadan siteyi şekillendirmenin en temiz yoludur. Action hook’lar olaylara tepki vermek için, filter hook’lar ise veriyi dönüştürmek için kullanılır. Bu iki kavramı kafanda oturttuğunda functions.php dosyan gerçekten güçlü bir araca dönüşür.

Özetlemek gerekirse:

  • Action kullan: Bir şey olduğunda başka bir şey yapmak istiyorsan
  • Filter kullan: Bir veriyi değiştirip geri vermek istiyorsan
  • Priority’e dikkat et: Aynı hook’a birden fazla fonksiyon bağlıysa sıra önemli
  • Filter’da return’ü unutma: Bu kuralı ihlal etmek production’da felaket demek
  • Kendi hook’larını yaz: Kodun genişletilebilirliği için olmazsa olmaz

Bu temeli sağlam attıktan sonra WooCommerce action’larını, Gutenberg filter’larını ve özel post type hook’larını çok daha rahat kullanmaya başlarsın. WordPress’in neredeyse her davranışı bir hook üzerinden kontrol edilebilir, sadece hangisini nerede kullanacağını bilmen gerekiyor.

Bir yanıt yazın

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