WooCommerce’de Eklentisiz Sepetteki İkinci Ürüne İndirim Uygulama

E-ticaret sitelerinde müşteri sadakati kazanmanın en etkili yollarından biri akıllı indirim stratejileri uygulamaktır. WooCommerce bu konuda güçlü bir altyapı sunar; ancak çoğu zaman “ikinci ürüne indirim” gibi spesifik ihtiyaçlar için ek eklenti kurmak zorunda kalırsınız. Oysa functions.php dosyasına birkaç satır kod ekleyerek bu işi tamamen eklentisiz halledebilirsiniz. Hem siteniz gereksiz eklenti yükünden kurtulur, hem de tam olarak istediğiniz davranışı elde edersiniz.

Neden Eklentisiz Yapmalıyız?

Bir WooCommerce sitesi yönetiyorsanız, eklenti şişkinliğinin ne kadar ciddi sorunlara yol açabileceğini bilirsiniz. Her eklenti ek HTTP isteği demektir, ek veritabanı sorgusu demektir ve potansiyel güvenlik açığı demektir.

“İkinci ürüne %50 indirim” tarzı kampanyalar için piyasada düzinelerce eklenti var. Bunların çoğu yüzlerce satır kod çalıştırıyor, kendi veritabanı tablolarını oluşturuyor ve ödeme sayfasını yavaşlatıyor. Halbuki bu mantığı functions.php ile kurduğunuzda:

  • Ek eklenti yükü yok
  • Tam kontrol sizde
  • Sitenizin diğer eklentileriyle çakışma riski minimum
  • Güncelleme derdi yok
  • Kodu istediğiniz gibi özelleştirebilirsiniz

Temel Mantık Nasıl Çalışır?

WooCommerce sepet hesaplamalarına müdahale etmenin birkaç yolu vardır. En temiz ve güvenilir yol woocommerce_cart_calculate_fees hook’unu kullanmaktır. Bu hook, sepet toplamı hesaplanırken tetiklenir ve siz burada negatif bir ücret (yani indirim) ekleyebilirsiniz.

Alternatif olarak woocommerce_before_calculate_totals hook’u da kullanılabilir; ancak bu hook ürün fiyatlarını doğrudan değiştirdiği için bazı durumlarda sepet görünümünde karışıklıklara yol açabilir. Ücret tabanlı yaklaşım daha temiz bir sonuç verir.

Senaryo 1: Sepetteki İkinci Ürüne Basit Yüzde İndirim

En yaygın senaryo şudur: Müşteri sepete 2 veya daha fazla ürün eklediğinde, en ucuz ürünün fiyatından belirli bir yüzde indirim uygula.

// functions.php dosyasina ekleyin
add_action( 'woocommerce_cart_calculate_fees', 'ikinci_urune_yuzde_indirim', 10, 1 );

function ikinci_urune_yuzde_indirim( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    $indirim_yuzdesi = 50; // %50 indirim
    $minimum_urun_sayisi = 2;

    // Sepetteki toplam urun adedini say
    $toplam_adet = $cart->get_cart_contents_count();

    if ( $toplam_adet < $minimum_urun_sayisi ) {
        return;
    }

    // Sepetteki urun fiyatlarini topla
    $fiyatlar = array();
    foreach ( $cart->get_cart() as $cart_item ) {
        $fiyat = $cart_item['data']->get_price();
        $miktar = $cart_item['quantity'];
        for ( $i = 0; $i < $miktar; $i++ ) {
            $fiyatlar[] = $fiyat;
        }
    }

    // Fiyatlari kucukten buyuge sirala
    sort( $fiyatlar );

    // En ucuz urune indirim uygula
    $indirim_tutari = $fiyatlar[0] * ( $indirim_yuzdesi / 100 );

    if ( $indirim_tutari > 0 ) {
        $cart->add_fee( 'İkinci Ürün İndirimi (%' . $indirim_yuzdesi . ')', -$indirim_tutari, true, '' );
    }
}

Bu kodun dikkat çekici noktaları şunlardır:

  • is_admin() kontrolü: Admin panelinde çalışmasını engeller, yalnızca frontend AJAX isteklerinde çalışır
  • sort($fiyatlar): En ucuz ürünü bulmak için fiyat dizisini sıralar
  • -$indirim_tutari: Negatif değer vermek WooCommerce’e bunun bir indirim olduğunu söyler
  • Üçüncü parametre true: İndirimin vergiye tabi olduğunu belirtir

Senaryo 2: En Pahalı Ürüne Değil, En Ucuz Ürüne İndirim

Bazı kampanyalarda “en pahalı olan ürünü tam fiyata al, ikincisini indirimli al” mantığı uygulanır. Bu durumda en ucuz ürüne indirim uygulamak daha avantajlıdır müşteri açısından. Ancak bazı markalar tam tersini yapar. Her iki seçeneği de görelim:

// En pahali urune indirim versiyonu
add_action( 'woocommerce_cart_calculate_fees', 'en_pahali_ikinci_urune_indirim', 10, 1 );

function en_pahali_ikinci_urune_indirim( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    $indirim_yuzdesi = 30;
    $toplam_adet = $cart->get_cart_contents_count();

    if ( $toplam_adet < 2 ) {
        return;
    }

    $fiyatlar = array();
    foreach ( $cart->get_cart() as $cart_item ) {
        $fiyat = floatval( $cart_item['data']->get_price() );
        $miktar = $cart_item['quantity'];
        for ( $i = 0; $i < $miktar; $i++ ) {
            $fiyatlar[] = $fiyat;
        }
    }

    // Buyukten kucuge sirala - en pahali urun basinda
    rsort( $fiyatlar );

    // Ikinci en pahali urune indirim uygula (index 1)
    if ( isset( $fiyatlar[1] ) ) {
        $indirim_tutari = $fiyatlar[1] * ( $indirim_yuzdesi / 100 );
        $cart->add_fee(
            'Kampanya: İkinci Ürün %' . $indirim_yuzdesi . ' İndirimli',
            -$indirim_tutari,
            true,
            ''
        );
    }
}

Senaryo 3: Belirli Kategorideki Ürünlere İndirim

Gerçek dünya projelerde genellikle “sadece Ayakkabı kategorisindeki ürünlerde geçerli” gibi kısıtlamalar olur. Bu durumu yönetmek için kategori kontrolü eklememiz gerekir:

add_action( 'woocommerce_cart_calculate_fees', 'kategori_bazli_ikinci_urun_indirimi', 10, 1 );

function kategori_bazli_ikinci_urun_indirimi( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    // Hangi kategoriler kampanyaya dahil?
    $hedef_kategoriler = array( 'ayakkabi', 'canta', 'aksesuar' );
    $indirim_yuzdesi   = 50;

    $kampanya_urunleri = array();

    foreach ( $cart->get_cart() as $cart_item ) {
        $product_id = $cart_item['product_id'];
        $urun_fiyati = floatval( $cart_item['data']->get_price() );

        // Bu urun hedef kategorilerde mi?
        if ( has_term( $hedef_kategoriler, 'product_cat', $product_id ) ) {
            $miktar = $cart_item['quantity'];
            for ( $i = 0; $i < $miktar; $i++ ) {
                $kampanya_urunleri[] = $urun_fiyati;
            }
        }
    }

    // Kampanya kategorisinde en az 2 urun olmali
    if ( count( $kampanya_urunleri ) < 2 ) {
        return;
    }

    sort( $kampanya_urunleri );

    $indirim_tutari = $kampanya_urunleri[0] * ( $indirim_yuzdesi / 100 );

    if ( $indirim_tutari > 0 ) {
        $cart->add_fee(
            'Seçili Kategorilerde İkinci Ürün İndirimi',
            -$indirim_tutari,
            true,
            ''
        );
    }
}

Bu örnekte has_term() fonksiyonu kritik rol oynuyor. WooCommerce kategorileri aslında WordPress taxonomy terimleridir; bu yüzden product_cat taxonomy adını kullanıyoruz.

Senaryo 4: Minimum Sepet Tutarı Şartıyla İndirim

Pek çok kampanyada “200 TL üzeri alışverişlerde ikinci ürüne indirim” gibi bir kural olur. Bunu da ekleyelim:

add_action( 'woocommerce_cart_calculate_fees', 'minimum_tutar_ile_ikinci_urun_indirimi', 10, 1 );

function minimum_tutar_ile_ikinci_urun_indirimi( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    $minimum_sepet_tutari = 500; // TL cinsinden
    $indirim_yuzdesi      = 50;
    $indirim_adi          = 'İkinci Ürüne %50 İndirim (500₺ Üzeri)';

    // Sepet ara toplamini kontrol et (vergi haric)
    $sepet_toplami = floatval( $cart->get_subtotal() );

    if ( $sepet_toplami < $minimum_sepet_tutari ) {
        return;
    }

    $toplam_adet = $cart->get_cart_contents_count();

    if ( $toplam_adet < 2 ) {
        return;
    }

    $fiyatlar = array();
    foreach ( $cart->get_cart() as $cart_item ) {
        $fiyat  = floatval( $cart_item['data']->get_price() );
        $miktar = $cart_item['quantity'];
        for ( $i = 0; $i < $miktar; $i++ ) {
            $fiyatlar[] = $fiyat;
        }
    }

    sort( $fiyatlar );

    $indirim_tutari = $fiyatlar[0] * ( $indirim_yuzdesi / 100 );

    if ( $indirim_tutari > 0 ) {
        $cart->add_fee( $indirim_adi, -$indirim_tutari, true, '' );
    }
}

Senaryo 5: Her İki Üründen Birini İndirimli Yapma (Çift Adet Kampanyası)

Bazen “4 ürün al, 2 tanesi yarı fiyat” gibi kampanyalar düzenlemek gerekir. Bu da sepetteki mantığı biraz daha karmaşık hale getirir:

add_action( 'woocommerce_cart_calculate_fees', 'cift_adet_kampanyasi', 10, 1 );

function cift_adet_kampanyasi( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    $indirim_yuzdesi = 50;
    $toplam_adet     = $cart->get_cart_contents_count();

    // En az 2 urun olmali
    if ( $toplam_adet < 2 ) {
        return;
    }

    $fiyatlar = array();
    foreach ( $cart->get_cart() as $cart_item ) {
        $fiyat  = floatval( $cart_item['data']->get_price() );
        $miktar = $cart_item['quantity'];
        for ( $i = 0; $i < $miktar; $i++ ) {
            $fiyatlar[] = $fiyat;
        }
    }

    sort( $fiyatlar );

    // Her 2 urunden biri indirimli (1., 3., 5. urunler indirimli)
    $indirim_uygulanan_sayisi = floor( count( $fiyatlar ) / 2 );
    $toplam_indirim           = 0;

    for ( $i = 0; $i < $indirim_uygulanan_sayisi; $i++ ) {
        $toplam_indirim += $fiyatlar[ $i ] * ( $indirim_yuzdesi / 100 );
    }

    if ( $toplam_indirim > 0 ) {
        $cart->add_fee(
            'Her 2 Üründen 1 Tanesi %' . $indirim_yuzdesi . ' İndirimli',
            -$toplam_indirim,
            true,
            ''
        );
    }
}

Senaryo 6: Sabit Tutar İndirim

Yüzde yerine sabit tutar da uygulayabilirsiniz. Örneğin “ikinci ürün 100 TL indirimli”:

add_action( 'woocommerce_cart_calculate_fees', 'sabit_tutar_ikinci_urun_indirimi', 10, 1 );

function sabit_tutar_ikinci_urun_indirimi( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    $sabit_indirim_tutari = 100; // TL cinsinden sabit indirim
    $toplam_adet          = $cart->get_cart_contents_count();

    if ( $toplam_adet < 2 ) {
        return;
    }

    $fiyatlar = array();
    foreach ( $cart->get_cart() as $cart_item ) {
        $fiyat  = floatval( $cart_item['data']->get_price() );
        $miktar = $cart_item['quantity'];
        for ( $i = 0; $i < $miktar; $i++ ) {
            $fiyatlar[] = $fiyat;
        }
    }

    sort( $fiyatlar );

    // En ucuz urun sabit indirimi karsiyabilmeli mi kontrol et
    $uygulanan_indirim = min( $sabit_indirim_tutari, $fiyatlar[0] );

    if ( $uygulanan_indirim > 0 ) {
        $cart->add_fee(
            'İkinci Ürüne 100₺ İndirim',
            -$uygulanan_indirim,
            true,
            ''
        );
    }
}

min() kullanımı burada çok önemli. Eğer ürün fiyatı 80 TL ise ve indirim 100 TL ise, ürün fiyatından fazla indirim uygulanmasını önlüyoruz.

Sepet Sayfasında Bilgilendirme Mesajı Gösterme

İndirim uygulandığında müşteriye görsel bir bildirim vermek hem kullanıcı deneyimini iyileştirir hem de kampanyayı daha belirgin hale getirir:

add_action( 'woocommerce_before_cart', 'ikinci_urun_kampanya_bildirimi' );

function ikinci_urun_kampanya_bildirimi() {
    $toplam_adet = WC()->cart->get_cart_contents_count();

    if ( $toplam_adet >= 2 ) {
        wc_print_notice(
            '🎉 Tebrikler! Sepetinizdeki en ucuz ürüne %50 indirim uygulandı.',
            'notice'
        );
    } else {
        $kalan = 2 - $toplam_adet;
        wc_print_notice(
            '🛍️ Sepetinize ' . $kalan . ' ürün daha ekleyin, ikinci ürüne %50 indirim kazanın!',
            'notice'
        );
    }
}

Önemli Teknik Notlar

Kodları functions.php dosyasına eklerken dikkat etmeniz gereken birkaç kritik nokta var:

  • is_admin() ve DOING_AJAX kontrolü: Bu ikisi birlikte kullanılmazsa admin sepet hesaplamalarında da kod çalışır ve beklenmedik sonuçlar doğurabilir
  • floatval() kullanımı: Fiyatları her zaman floatval() ile sayısal değere çevirip kullanın, string işlem hataları yaşanmasın
  • Vergi uyumluluğu: add_fee() fonksiyonunun üçüncü parametresi true olduğunda indirim vergiye tabi tutulur. Eğer indirim vergi dışında kalmalıysa false yapın
  • Çakışan kuponlar: Eğer WooCommerce kupon sistemiyle birlikte kullanıyorsanız, her ikisinin de aktif olup olmadığını kontrol eden bir mekanizma kurun
  • Test ortamında deneyin: Canlıya almadan önce staging ortamında mutlaka test edin
  • Child theme kullanımı: Bu kodları doğrudan ana temanın functions.php dosyasına değil, mutlaka child theme’in functions.php dosyasına ekleyin

Performans İpuçları

Sepet her güncellendiğinde bu fonksiyon çalışacaktır. Büyük kataloglarda performansı etkiler mi diye sorabilirsiniz. Birkaç önlem alabilirsiniz:

// Sonuclari gecici olarak cache'le
add_action( 'woocommerce_cart_calculate_fees', 'optimize_edilmis_ikinci_urun_indirimi', 10, 1 );

function optimize_edilmis_ikinci_urun_indirimi( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    $toplam_adet = $cart->get_cart_contents_count();

    if ( $toplam_adet < 2 ) {
        return;
    }

    // Sepet hash'ini kullanarak tekrar hesaplamaktan kacin
    $cart_hash     = md5( serialize( $cart->get_cart() ) );
    $cached_result = get_transient( 'ikinci_urun_indirim_' . $cart_hash );

    if ( false !== $cached_result ) {
        $cart->add_fee( 'İkinci Ürün İndirimi', -$cached_result, true, '' );
        return;
    }

    $fiyatlar = array();
    foreach ( $cart->get_cart() as $cart_item ) {
        $fiyat  = floatval( $cart_item['data']->get_price() );
        $miktar = $cart_item['quantity'];
        for ( $i = 0; $i < $miktar; $i++ ) {
            $fiyatlar[] = $fiyat;
        }
    }

    sort( $fiyatlar );
    $indirim_tutari = $fiyatlar[0] * 0.50;

    // 1 saatlik cache
    set_transient( 'ikinci_urun_indirim_' . $cart_hash, $indirim_tutari, HOUR_IN_SECONDS );

    if ( $indirim_tutari > 0 ) {
        $cart->add_fee( 'İkinci Ürün İndirimi', -$indirim_tutari, true, '' );
    }
}

Sık Karşılaşılan Sorunlar ve Çözümleri

Kodları uyguladığınızda karşılaşabileceğiniz sorunlar ve çözümleri:

  • İndirim görünmüyor: woocommerce_cart_calculate_fees hook’unun doğru priority değeriyle eklendiğinden emin olun. Başka bir eklenti aynı hook’u override edebilir
  • İndirim çift uygulanıyor: Aynı fonksiyonu birden fazla kez add_action ile bağlamış olabilirsiniz. remove_action ile önce mevcut bağı kaldırın
  • Vergi hesaplamalarında tutarsızlık: add_fee() parametrelerini gözden geçirin, vergiye tabi/değil ayarını kontrol edin
  • Negatif sepet toplamı: min() fonksiyonuyla indirim tutarının hiçbir zaman ürün fiyatından fazla olmamasını garantileyin
  • Admin siparişlerinde hata: is_admin() kontrolünü eklediğinizden emin olun

Sonuç

functions.php ile WooCommerce sepetine ikinci ürün indirimi eklemek, eklentilere göre çok daha esnek ve kontrol edilebilir bir yaklaşımdır. Temel mantık basittir: sepetteki ürünleri listele, sırala, hedef ürünü belirle ve negatif ücret olarak indirim uygula.

Yukarıdaki senaryoları kendi ihtiyacınıza göre birleştirebilirsiniz. Kategori filtresi + minimum sepet tutarı + yüzde indirim üçlüsünü bir araya getirerek oldukça sofistike kampanyalar kurabilirsiniz. Önemli olan şey her zaman edge case’leri düşünmektir: ürün fiyatından fazla indirim, tek ürünlü sepet, sıfır fiyatlı ürünler gibi durumları mutlaka test edin.

Bu yaklaşımın en büyük avantajı, sizi eklenti bağımlılığından kurtarmasıdır. Yarın eklenti geliştiricisi desteği keserse veya ücretli hale geçerse, sizin kodunuz çalışmaya devam eder. Sysadmin perspektifinden bakıldığında, ne kadar az eklenti o kadar az baş ağrısı.

Bir yanıt yazın

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