WooCommerce Ürün Sayfasına Özel Sekme Ekleme

E-ticaret sitenizde ürün sayfaları, müşterinin satın alma kararını verdiği en kritik noktalardır. WooCommerce varsayılan olarak “Açıklama”, “Ek Bilgiler” ve “Yorumlar” sekmelerini sunar, ancak çoğu zaman bu üç sekme yetmez. Belki kargo bilgilerini ayrı bir sekmede göstermek istiyorsunuzdur, belki ürüne özel SSS eklemek, belki de garanti koşullarını ayrı tutmak istiyorsunuzdur. İşte tam bu noktada functions.php devreye giriyor ve birkaç satır kod ile istediğiniz sekmeyi ekleyebiliyorsunuz.

WooCommerce Sekme Sistemi Nasıl Çalışır?

WooCommerce ürün sayfasındaki sekmeler, woocommerce_product_tabs filtresi üzerinden yönetilir. Bu filtre bir dizi döndürür ve bu dizideki her eleman bir sekmeyi temsil eder. Her sekme elemanı şu bileşenlere sahiptir:

  • title: Sekmenin başlık metni
  • priority: Hangi sırada görüneceği (küçük sayı = öne gelir)
  • callback: Sekme içeriğini render eden fonksiyon

Bu yapıyı anladıktan sonra hem yeni sekme eklemek, hem var olanları düzenlemek, hem de tamamen kaldırmak son derece kolay hale gelir. Şimdi adım adım gerçek dünya senaryolarıyla ilerleyelim.

Temel Sekme Ekleme

En basit haliyle özel bir sekme eklemek için functions.php dosyanıza şunu yazmanız yeterli:

// functions.php
add_filter( 'woocommerce_product_tabs', 'ozel_sekme_ekle' );

function ozel_sekme_ekle( $tabs ) {
    $tabs['ozel_bilgi'] = array(
        'title'    => __( 'Özel Bilgiler', 'woocommerce' ),
        'priority' => 50,
        'callback' => 'ozel_sekme_icerik'
    );
    return $tabs;
}

function ozel_sekme_icerik() {
    echo '<h2>Özel Bilgiler</h2>';
    echo '<p>Bu sekmeye istediğiniz içeriği ekleyebilirsiniz.</p>';
}

Bu kod parçasıyla “Özel Bilgiler” başlıklı yeni bir sekme eklediniz. Priority değeri 50 olduğu için varsayılan sekmelerin arasına ya da sonuna düşer. Açıklama sekmesi 10, Ek Bilgiler 20, Yorumlar 30 priority değerine sahiptir. Buna göre 50 değeriyle sekmeniz en sona gider.

Mevcut Sekmeleri Düzenleme veya Kaldırma

Bazen yerleşik sekmelerin başlıklarını değiştirmek ya da birini tamamen kaldırmak gerekir. Özellikle sadece basit ürünler satan bir sitede “Ek Bilgiler” sekmesi gereksiz görünebilir.

add_filter( 'woocommerce_product_tabs', 'sekmeleri_duzenle', 98 );

function sekmeleri_duzenle( $tabs ) {

    // Açıklama sekmesi başlığını değiştir
    if ( isset( $tabs['description'] ) ) {
        $tabs['description']['title'] = 'Ürün Detayı';
    }

    // Ek Bilgiler sekmesini kaldır
    unset( $tabs['additional_information'] );

    // Yorumlar sekmesi başlığını değiştir
    if ( isset( $tabs['reviews'] ) ) {
        $tabs['reviews']['title'] = 'Müşteri Yorumları';
    }

    return $tabs;
}

Burada filtre önceliğini 98 verdik. WooCommerce sekmeleri 10 önceliğiyle yükler, biz ondan sonra devreye girip değişiklik yapıyoruz. Bu detay sık gözden kaçan bir noktadır ve hata ayıklamada zaman kaybetmenize neden olabilir.

Kargo Bilgileri Sekmesi – Gerçek Dünya Senaryosu

Bir müşteri ürün sayfasına girdiğinde ilk sorduğu şeylerden biri “bu ne zaman gelir?” sorusudur. Kargo bilgilerini ayrı ve görünür bir sekmede göstermek dönüşüm oranlarını ciddi ölçüde artırır. İşte bunu yapmanın profesyonel yolu:

add_filter( 'woocommerce_product_tabs', 'kargo_sekme_ekle' );

function kargo_sekme_ekle( $tabs ) {
    $tabs['kargo_bilgi'] = array(
        'title'    => 'Kargo & Teslimat',
        'priority' => 25,
        'callback' => 'kargo_sekme_render'
    );
    return $tabs;
}

function kargo_sekme_render() {
    global $product;

    $agirlik  = $product->get_weight();
    $boyutlar = $product->get_dimensions( false );

    echo '<h2>Kargo ve Teslimat Bilgileri</h2>';

    echo '<div class="kargo-bilgi-wrapper">';

    echo '<h3>Teslimat Süreleri</h3>';
    echo '<ul>';
    echo '<li><strong>Standart Kargo:</strong> 3-5 iş günü</li>';
    echo '<li><strong>Hızlı Kargo:</strong> 1-2 iş günü</li>';
    echo '<li><strong>Ücretsiz Kargo:</strong> 500 TL üzeri siparişlerde geçerlidir</li>';
    echo '</ul>';

    if ( $agirlik ) {
        echo '<h3>Ürün Ağırlığı</h3>';
        echo '<p>' . esc_html( $agirlik ) . ' kg</p>';
    }

    if ( ! empty( $boyutlar ) ) {
        echo '<h3>Ürün Boyutları</h3>';
        echo '<p>' . esc_html( wc_format_dimensions( $boyutlar ) ) . '</p>';
    }

    echo '<h3>İade Politikası</h3>';
    echo '<p>Ürünü teslim aldıktan sonra 14 gün içinde iade edebilirsiniz. ';
    echo 'İade kargosunu biz karşılıyoruz.</p>';

    echo '</div>';
}

Bu örnekte ürünün WooCommerce veritabanındaki ağırlık ve boyut bilgilerini dinamik olarak çektik. Bu sayede her ürün için farklı bilgiler otomatik görünür.

Ürüne Özel İçerik – Custom Field ile Sekme

Bazı durumlarda her ürün için farklı sekme içeriği göstermek istersiniz. Örneğin teknik özellikler sekmesi, her ürün için farklı veriler içerir. Bunu ürün meta alanları üzerinden yönetebilirsiniz:

// Admin panelinde ürün düzenleme sayfasına meta alan ekle
add_action( 'woocommerce_product_options_general_product_data', 'teknik_bilgi_alani_ekle' );

function teknik_bilgi_alani_ekle() {
    woocommerce_wp_textarea_input(
        array(
            'id'          => '_teknik_ozellikler',
            'label'       => 'Teknik Özellikler',
            'placeholder' => 'Teknik özellikler sekme içeriğini buraya yazın...',
            'desc_tip'    => true,
            'description' => 'Bu içerik ürün sayfasında Teknik Özellikler sekmesinde görünür.',
            'rows'        => 5,
        )
    );
}

// Meta alanı kaydet
add_action( 'woocommerce_process_product_meta', 'teknik_bilgi_kaydet' );

function teknik_bilgi_kaydet( $post_id ) {
    $teknik_veri = isset( $_POST['_teknik_ozellikler'] ) 
        ? sanitize_textarea_field( $_POST['_teknik_ozellikler'] ) 
        : '';
    update_post_meta( $post_id, '_teknik_ozellikler', $teknik_veri );
}

// Sekmeyi ekle - sadece içerik doluysa göster
add_filter( 'woocommerce_product_tabs', 'teknik_sekme_ekle' );

function teknik_sekme_ekle( $tabs ) {
    global $product;

    $teknik_icerik = get_post_meta( $product->get_id(), '_teknik_ozellikler', true );

    if ( ! empty( $teknik_icerik ) ) {
        $tabs['teknik_ozellikler'] = array(
            'title'    => 'Teknik Özellikler',
            'priority' => 15,
            'callback' => 'teknik_sekme_render'
        );
    }

    return $tabs;
}

function teknik_sekme_render() {
    global $product;
    $teknik_icerik = get_post_meta( $product->get_id(), '_teknik_ozellikler', true );

    if ( $teknik_icerik ) {
        echo '<h2>Teknik Özellikler</h2>';
        echo '<div class="teknik-ozellikler">';
        echo wpautop( wp_kses_post( $teknik_icerik ) );
        echo '</div>';
    }
}

Bu yaklaşımın güzelliği şu: İçeriği boş olan ürünlerde sekme hiç görünmez. Gereksiz boş sekmelerle kullanıcıyı rahatsız etmezsiniz. Admin panelinden her ürün için kolayca içerik girebilirsiniz.

Kategori Bazlı Sekme Gösterimi

Belirli bir ürün kategorisine ait ürünlerde özel sekme göstermek, çok kategorili büyük e-ticaret sitelerinde sıklıkla ihtiyaç duyulan bir senaryodur. Diyelim ki sadece “elektronik” kategorisindeki ürünlerde garanti bilgileri sekmesi çıksın:

add_filter( 'woocommerce_product_tabs', 'kategori_bazli_sekme_ekle' );

function kategori_bazli_sekme_ekle( $tabs ) {
    global $product;

    // Ürün belirli kategoride mi kontrol et
    $hedef_kategoriler = array( 'elektronik', 'bilgisayar', 'telefon' );

    if ( has_term( $hedef_kategoriler, 'product_cat', $product->get_id() ) ) {
        $tabs['garanti_bilgi'] = array(
            'title'    => 'Garanti Koşulları',
            'priority' => 30,
            'callback' => 'garanti_sekme_render'
        );
    }

    return $tabs;
}

function garanti_sekme_render() {
    echo '<h2>Garanti Koşulları</h2>';

    echo '<div class="garanti-bilgi">';
    echo '<h3>Standart Garanti Kapsamı</h3>';
    echo '<ul>';
    echo '<li>Tüm elektronik ürünlerimiz <strong>2 yıl resmi distribütör garantisi</strong> ile gelir</li>';
    echo '<li>Garanti belgesi ürünle birlikte teslim edilir</li>';
    echo '<li>Arıza durumunda yetkili servise yönlendirme yapılır</li>';
    echo '<li>Hasar görmüş, kırılmış veya ıslatılmış ürünler garanti kapsamı dışındadır</li>';
    echo '</ul>';

    echo '<h3>Garanti Süreci</h3>';
    echo '<p>Garanti kapsamındaki arızalar için <strong>0850 XXX XX XX</strong> numaralı ';
    echo 'hattımızı arayabilir ya da [email protected] adresine mail atabilirsiniz.</p>';
    echo '</div>';
}

SSS Sekmesi ile Müşteri Sorularını Yönetmek

Müşteri destek yükünü azaltmanın en etkili yollarından biri sık sorulan soruları ürün sayfasında görünür kılmaktır. Advanced Custom Fields (ACF) kullanıyorsanız bu işi çok daha temiz yapabilirsiniz. Ancak sadece core WordPress ile de çözebilirsiniz:

// SSS için repeater benzeri bir yapı - JSON olarak meta'da sakla
add_action( 'woocommerce_product_options_advanced', 'sss_alanlari_ekle' );

function sss_alanlari_ekle() {
    global $post;
    $sss_listesi = get_post_meta( $post->ID, '_urun_sss', true );
    $sss_listesi = $sss_listesi ? json_decode( $sss_listesi, true ) : array();

    echo '<div class="options_group">';
    echo '<p class="form-field"><label>Sık Sorulan Sorular</label></p>';
    echo '<div id="sss-container">';

    if ( ! empty( $sss_listesi ) ) {
        foreach ( $sss_listesi as $index => $sss ) {
            echo '<div class="sss-item" style="margin-bottom:10px; padding:10px; background:#f5f5f5;">';
            echo '<input type="text" name="sss_soru[]" placeholder="Soru" ';
            echo 'value="' . esc_attr( $sss['soru'] ) . '" style="width:100%;margin-bottom:5px;" />';
            echo '<textarea name="sss_cevap[]" placeholder="Cevap" style="width:100%;">';
            echo esc_textarea( $sss['cevap'] ) . '</textarea>';
            echo '</div>';
        }
    }

    echo '</div>';
    echo '<button type="button" id="sss-ekle-btn" class="button">+ Soru Ekle</button>';
    echo '</div>';

    // Basit JS ile dinamik alan ekleme
    ?>
    <script>
    jQuery(document).ready(function($){
        $('#sss-ekle-btn').on('click', function(){
            var html = '<div class="sss-item" style="margin-bottom:10px;padding:10px;background:#f5f5f5;">';
            html += '<input type="text" name="sss_soru[]" placeholder="Soru" style="width:100%;margin-bottom:5px;" />';
            html += '<textarea name="sss_cevap[]" placeholder="Cevap" style="width:100%;"></textarea>';
            html += '</div>';
            $('#sss-container').append(html);
        });
    });
    </script>
    <?php
}

add_action( 'woocommerce_process_product_meta', 'sss_kaydet' );

function sss_kaydet( $post_id ) {
    $sorular = isset( $_POST['sss_soru'] ) ? $_POST['sss_soru'] : array();
    $cevaplar = isset( $_POST['sss_cevap'] ) ? $_POST['sss_cevap'] : array();

    $sss_listesi = array();
    foreach ( $sorular as $index => $soru ) {
        if ( ! empty( $soru ) && isset( $cevaplar[ $index ] ) ) {
            $sss_listesi[] = array(
                'soru'  => sanitize_text_field( $soru ),
                'cevap' => sanitize_textarea_field( $cevaplar[ $index ] )
            );
        }
    }

    update_post_meta( $post_id, '_urun_sss', wp_json_encode( $sss_listesi ) );
}

// SSS Sekmesi
add_filter( 'woocommerce_product_tabs', 'sss_sekme_ekle' );

function sss_sekme_ekle( $tabs ) {
    global $product;
    $sss_listesi = get_post_meta( $product->get_id(), '_urun_sss', true );
    $sss_listesi = $sss_listesi ? json_decode( $sss_listesi, true ) : array();

    if ( ! empty( $sss_listesi ) ) {
        $tabs['urun_sss'] = array(
            'title'    => 'Sık Sorulan Sorular (' . count( $sss_listesi ) . ')',
            'priority' => 40,
            'callback' => 'sss_sekme_render'
        );
    }

    return $tabs;
}

function sss_sekme_render() {
    global $product;
    $sss_listesi = get_post_meta( $product->get_id(), '_urun_sss', true );
    $sss_listesi = $sss_listesi ? json_decode( $sss_listesi, true ) : array();

    if ( empty( $sss_listesi ) ) return;

    echo '<h2>Sık Sorulan Sorular</h2>';
    echo '<div class="urun-sss-listesi">';

    foreach ( $sss_listesi as $sss ) {
        echo '<div class="sss-item">';
        echo '<h4 class="sss-soru"><strong>S: ' . esc_html( $sss['soru'] ) . '</strong></h4>';
        echo '<p class="sss-cevap">C: ' . esc_html( $sss['cevap'] ) . '</p>';
        echo '</div>';
    }

    echo '</div>';
}

Sekme başlığında parantez içinde soru sayısını göstermek küçük ama etkili bir UX detayıdır. Kullanıcı tıklamadan ne kadar içerik olduğunu görür.

Template Dosyasını Kullanarak Daha Temiz Sekme İçeriği

Uzun HTML içerikleri fonksiyon içinde echo ile yazmak hem okunaksız hem de bakımı zor hale gelir. Tema klasörünüzde bir template dosyası kullanmak çok daha profesyonel bir yaklaşımdır:

// Tema klasöründe woocommerce/tabs/kargo.php dosyası oluşturun
// Sonra callback fonksiyonunuzda şunu kullanın:

function kargo_sekme_template_render() {
    global $product;

    // Önce child tema klasöründe ara, yoksa ana temada bak
    $template = locate_template( 
        array( 'woocommerce/tabs/kargo.php' ) 
    );

    if ( $template ) {
        include $template;
    } else {
        // Fallback içerik
        echo '<p>Kargo bilgileri yükleniyor...</p>';
    }
}

// Alternatif olarak plugin ya da tema klasöründen direkt yükle
function garanti_sekme_template_render() {
    global $product;

    $template_path = get_stylesheet_directory() . '/woocommerce/tabs/garanti.php';

    if ( file_exists( $template_path ) ) {
        include $template_path;
    }
}

woocommerce/tabs/garanti.php dosyasının içeriği:

<?php
// woocommerce/tabs/garanti.php
// Bu dosyada $product global değişkeni erişilebilir durumdadır

defined( 'ABSPATH' ) || exit;

$urun_id      = $product->get_id();
$garanti_sure = get_post_meta( $urun_id, '_garanti_suresi', true ) ?: '24 ay';
?>

<h2><?php echo esc_html__( 'Garanti Bilgileri', 'woocommerce' ); ?></h2>

<div class="garanti-wrapper">
    <p>Bu ürün <strong><?php echo esc_html( $garanti_sure ); ?></strong> garanti ile gelmektedir.</p>

    <h3>Garanti Koşulları</h3>
    <ul>
        <li>Garanti, üretim hatalarını kapsar</li>
        <li>Kullanıcı kaynaklı hasarlar garanti dışındadır</li>
        <li>Garanti belgesi ile başvuru yapılması zorunludur</li>
    </ul>
</div>

Bu yaklaşım ile PHP, HTML ve iş mantığını birbirinden ayırmış olursunuz.

Performans İçin Dikkat Edilmesi Gerekenler

Sekme içerikleri her ürün sayfası yüklendiğinde çalışır. Eğer sekme içeriğiniz harici bir API’ye istek atıyorsa ya da ağır database sorguları içeriyorsa ciddi yavaşlamalar yaşayabilirsiniz. Bu durumda transient önbelleği kullanmak şarttır:

function agir_sekme_icerik_render() {
    global $product;
    $urun_id      = $product->get_id();
    $cache_key    = 'ozel_sekme_icerik_' . $urun_id;
    $cached_icerik = get_transient( $cache_key );

    if ( false !== $cached_icerik ) {
        echo $cached_icerik; // phpcs:ignore WordPress.Security.EscapeOutput
        return;
    }

    ob_start();

    // Ağır işlemler burada
    $veri = agir_veri_cek_fonksiyonu( $urun_id );

    echo '<h2>Detaylı Analiz</h2>';
    echo '<div class="analiz-wrapper">';
    echo wp_kses_post( $veri );
    echo '</div>';

    $icerik = ob_get_clean();

    // 12 saat boyunca önbelleğe al
    set_transient( $cache_key, $icerik, 12 * HOUR_IN_SECONDS );

    echo $icerik; // phpcs:ignore WordPress.Security.EscapeOutput
}

// Ürün güncellendiğinde önbelleği temizle
add_action( 'woocommerce_update_product', 'sekme_onbellegi_temizle' );

function sekme_onbellegi_temizle( $urun_id ) {
    delete_transient( 'ozel_sekme_icerik_' . $urun_id );
}

Transient kullanımında dikkat edilmesi gereken bir nokta: Ürün güncellendiğinde eski önbellekten servis etmemek için mutlaka temizleme hook’unu eklemelisiniz.

Yaygın Hatalar ve Çözümleri

Sekme ekleme işlemlerinde en sık karşılaşılan sorunları ve çözümlerini listeleyelim:

  • Sekme görünmüyor: woocommerce_product_tabs filtresi yerine yanlış hook kullanılmış olabilir. Ayrıca cache eklentileri sekmeyi göstermeyebilir, önce cache’i temizleyin.
  • Sekme başlığı Türkçe karakter sorunu: __() veya _e() kullanırken text domain doğru tanımlanmamış olabilir. Doğrudan string yazmak en güvenli yol.
  • Priority çakışması: Başka bir eklenti aynı priority ile sekme ekliyorsa çakışma olabilir. 35, 45, 55 gibi kullanılmayan değerleri tercih edin.
  • $product erişilemiyor: Global $product değişkeni bazı durumlarda null gelebilir. wc_get_product( get_the_ID() ) ile güvenli şekilde alın.
  • Sekme içeriği XSS açığı: Kullanıcıdan veya veritabanından gelen her veriyi esc_html(), esc_attr() veya wp_kses_post() ile temizleyin.

Sonuç

WooCommerce sekme sistemi, son derece esnek ve geliştiriciye dostane bir yapıya sahip. woocommerce_product_tabs filtresi tek bir hook ile hem ekleme, hem düzenleme hem de kaldırma işlemlerini mümkün kılıyor.

Pratikte en işe yarayan yaklaşım şu şekilde özetlenebilir: Basit ve statik içerikler için direkt callback fonksiyonu yeterli. Ürüne özel dinamik içerikler için post meta alanları ile birlikte çalışın. Karmaşık HTML yapıları için template dosyası kullanın. Ve performans kritikse transient önbelleklemeyi ihmal etmeyin.

Bu teknikleri bir kez kavradıktan sonra ürün sayfalarınızı müşterinizin gerçekten ihtiyaç duyduğu bilgilere göre şekillendirebilir, hem kullanıcı deneyimini iyileştirebilir hem de destek yükünüzü önemli ölçüde azaltabilirsiniz. Kargo bilgisi, garanti şartları, teknik özellikler, SSS, video içerikleri… bunların hepsi artık tam anlamıyla kontrol altında.

Bir yanıt yazın

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