WooCommerce Ürün Sayfasının Sonuna İçerik Ekleme
E-ticaret sitelerinde ürün sayfaları, müşteri kararlarını doğrudan etkileyen en kritik noktalardır. WooCommerce varsayılan olarak gayet işlevsel bir ürün sayfası sunar ama gerçek dünyada bu yeterli olmaz. Kargo bilgileri, garanti şartları, özel kampanya metinleri, güven rozetleri veya çapraz satış mesajları gibi içerikleri ürün sayfasının sonuna eklemek istediğinizde, doğru hook’ları ve functions.php yaklaşımını bilmek hem hızınızı hem de sitenizin sağlığını korur.
WooCommerce Hook Mimarisini Anlamak
WooCommerce, ürün sayfalarını modüler bir hook sistemiyle oluşturur. Bu hook’lar, tema dosyalarına dokunmadan içerik eklemenizi sağlar. Tema güncellemesi yaptığınızda özelleştirmeleriniz kaybolmaz çünkü her şey functions.php veya özel bir eklenti dosyasında yaşar.
Ürün sayfasının sonuna içerik eklemek için en çok kullanılan hook’lar şunlardır:
- woocommerce_after_single_product: Tüm ürün sayfasının en sonunda tetiklenir,
Bu hook’ların hangisini kullanacağınız tamamen ne tür bir içerik eklediğinize bağlıdır. Kargo ve garanti bilgileri için woocommerce_after_single_product_summary çoğu zaman en mantıklı seçimdir. Sayfa genelini etkileyen promosyon bantları veya yasal uyarılar içinse woocommerce_after_single_product daha uygundur.
Temel İçerik Ekleme: İlk Kod Örneği
En basit senaryodan başlayalım. Diyelim ki tüm ürün sayfalarının sonuna bir güven mesajı eklemek istiyorsunuz.
// functions.php dosyasına ekleyin
add_action( 'woocommerce_after_single_product', 'ozel_guven_mesaji_ekle', 10 );
function ozel_guven_mesaji_ekle() {
echo '<div class="guven-mesaji">';
echo '<p>Tüm siparişleriniz 256-bit SSL şifreleme ile korunmaktadır.</p>';
echo '</div>';
}
Bu kadar basit. add_action fonksiyonundaki 10 parametresi önceliği belirtir. Daha büyük sayı, daha geç çalışır demektir. Eğer başka eklentiler de aynı hook’u kullanıyorsa öncelik sıralaması önem kazanır.
Sadece Belirli Kategorilerde İçerik Göstermek
Gerçek dünya senaryolarında genellikle tüm ürünlere değil, belirli kategorilere ait ürünlere özel içerik eklemek gerekir. Mesela elektronik kategorisindeki ürünler için “2 yıl üretici garantisi” notu eklemek, gıda kategorisindeki ürünler için son kullanma tarihi uyarısı göstermek bunların klasik örnekleridir.
add_action( 'woocommerce_after_single_product_summary', 'kategori_bazli_icerik_ekle', 15 );
function kategori_bazli_icerik_ekle() {
global $post;
// Ürün elektronik kategorisinde mi?
if ( has_term( 'elektronik', 'product_cat', $post->ID ) ) {
echo '<div class="garanti-bilgisi">';
echo '<h3>Üretici Garantisi</h3>';
echo '<p>Bu ürün, üretici firması tarafından 2 yıl garanti kapsamındadır.</p>';
echo '<p>Garanti işlemleri için ürün kutusundaki garanti belgesini saklayınız.</p>';
echo '</div>';
}
// Gıda kategorisindeyse farklı içerik
if ( has_term( 'gida', 'product_cat', $post->ID ) ) {
echo '<div class="gida-uyari">';
echo '<p><strong>Önemli:</strong> Ürünü serin ve kuru yerde saklayınız.</p>';
echo '</div>';
}
}
has_term fonksiyonu hem kategori slug’ını hem de ID’sini kabul eder. Slug kullanmak daha güvenlidir çünkü ID’ler farklı sunuculara taşıma sırasında değişebilir.
Ürün Meta Verilerine Göre Dinamik İçerik
WooCommerce ürünlerine özel meta alanları ekleyebilir ve bu alanlardaki verilere göre dinamik içerikler oluşturabilirsiniz. Özellikle ACF (Advanced Custom Fields) veya WooCommerce’in kendi meta sistemi ile birlikte bu yaklaşım çok güçlüdür.
add_action( 'woocommerce_after_single_product_summary', 'ozel_meta_icerik_goster', 20 );
function ozel_meta_icerik_goster() {
global $product;
// Ürün nesnesini al
if ( ! $product ) {
$product = wc_get_product( get_the_ID() );
}
// Özel meta değerini çek
$kargo_suresi = get_post_meta( $product->get_id(), '_ozel_kargo_suresi', true );
$uretim_yeri = get_post_meta( $product->get_id(), '_uretim_yeri', true );
if ( $kargo_suresi || $uretim_yeri ) {
echo '<div class="ozel-urun-bilgileri">';
echo '<h3>Ürün Detayları</h3>';
if ( $kargo_suresi ) {
echo '<p><strong>Tahmini Kargo Süresi:</strong> ' . esc_html( $kargo_suresi ) . ' iş günü</p>';
}
if ( $uretim_yeri ) {
echo '<p><strong>Üretim Yeri:</strong> ' . esc_html( $uretim_yeri ) . '</p>';
}
echo '</div>';
}
}
Burada esc_html() kullanımına dikkat edin. Veritabanından gelen her veriyi ekrana basmadan önce escape etmek güvenlik açısından zorunludur. Bu küçük alışkanlık, XSS saldırılarına karşı sitenizi korur.
Stok Durumuna Göre Özel Mesajlar
Stok yönetimi aktif olan mağazalarda, stok durumuna göre dinamik mesajlar göstermek dönüşüm oranlarını ciddi artırır. “Son 3 ürün kaldı” gibi mesajlar aciliyet hissi yaratır.
add_action( 'woocommerce_after_single_product_summary', 'stok_uyari_mesaji', 12 );
function stok_uyari_mesaji() {
global $product;
if ( ! $product ) {
$product = wc_get_product( get_the_ID() );
}
// Stok yönetimi aktif mi?
if ( ! $product->managing_stock() ) {
return;
}
$stok_miktari = $product->get_stock_quantity();
if ( $stok_miktari === null ) {
return;
}
if ( $stok_miktari <= 5 && $stok_miktari > 0 ) {
echo '<div class="stok-uyari kritik">';
echo '<p>⚡ <strong>Son ' . intval( $stok_miktari ) . ' ürün kaldı!</strong> Stoklarımız hızla tükeniyor.</p>';
echo '</div>';
} elseif ( $stok_miktari <= 20 && $stok_miktari > 5 ) {
echo '<div class="stok-uyari dusuk">';
echo '<p>Stokta sadece <strong>' . intval( $stok_miktari ) . ' adet</strong> bulunmaktadır.</p>';
echo '</div>';
} elseif ( $stok_miktari > 20 ) {
echo '<div class="stok-uyari yeterli">';
echo '<p>✓ Bu ürün stokta mevcut. Siparişiniz aynı gün hazırlanır.</p>';
echo '</div>';
}
}
intval() kullanımı burada kritik. Veritabanından gelen stok değerini integer’a çevirmek hem güvenlik hem de doğruluk açısından önemlidir.
Kullanıcı Rolüne Göre İçerik Kontrolü
Toptan satış yapan WooCommerce sitelerinde veya üyelik sistemlerinde kullanıcı rolüne göre farklı içerik göstermek sık karşılaşılan bir ihtiyaçtır. B2B müşterilere fatura bilgileri, standart müşterilere üyelik teşvik mesajları göstermek buna güzel bir örnektir.
add_action( 'woocommerce_after_single_product', 'rol_bazli_icerik_goster', 10 );
function rol_bazli_icerik_goster() {
// Giriş yapmış kullanıcı kontrolü
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
// Toptan müşteri rolü kontrolü
if ( in_array( 'toptan_musteri', $current_user->roles ) ) {
echo '<div class="toptan-bilgi">';
echo '<h3>Toptan Satış Bilgileri</h3>';
echo '<p>Toptan fiyat listesi için satış temsilcinizle iletişime geçin.</p>';
echo '<p>E-fatura kesimi için: <strong>[email protected]</strong></p>';
echo '</div>';
return;
}
// Normal giriş yapmış kullanıcı
echo '<div class="uye-tesekkur">';
echo '<p>Üye indirimleri için sepetinizi kontrol etmeyi unutmayın!</p>';
echo '</div>';
} else {
// Giriş yapmamış kullanıcı - üyelik teşviki
echo '<div class="uyelik-tesvik">';
echo '<p>🎁 <a href="' . esc_url( wp_login_url() ) . '">Üye girişi</a> yaparak özel fiyatlardan yararlanın!</p>';
echo '</div>';
}
}
İlgili Ürünlerin Ardından İçerik Eklemek
Bazen içeriği sayfanın gerçekten en sonuna, yani ilgili ürünler bölümünden sonra eklemek istersiniz. Newsletter kayıt alanı, marka hikayesi veya sosyal medya linkleri için bu hook idealdir.
add_action( 'woocommerce_after_related_products', 'sayfa_sonu_icerik', 10 );
function sayfa_sonu_icerik() {
?>
<div class="sayfa-sonu-bolumu">
<div class="marka-hakkinda">
<h3>Neden Bizi Tercih Etmelisiniz?</h3>
<ul>
<li>15 yıllık sektör deneyimi</li>
<li>100.000+ mutlu müşteri</li>
<li>7/24 müşteri destek hattı</li>
<li>30 gün koşulsuz iade garantisi</li>
</ul>
</div>
<div class="iletisim-kisayol">
<p>Sorularınız mı var?
<a href="<?php echo esc_url( get_permalink( get_page_by_path( 'iletisim' ) ) ); ?>">
Bize ulaşın
</a>
</p>
</div>
</div>
<?php
}
PHP heredoc veya inline HTML sözdizimi, uzun HTML bloklarında echo zincirine göre çok daha okunaklıdır. Büyük ekiplerde çalışıyorsanız bu yaklaşım kod incelemeleri sırasında büyük kolaylık sağlar.
CSS ile Eklenen İçeriği Stillendirmek
İçerik eklemenin yanı sıra bu içeriklere stil vermek de aynı dosya üzerinden yapılabilir. Ancak doğru yöntem CSS’i doğrudan echo etmek değil, WordPress’in enqueue sistemini kullanmaktır.
// CSS dosyasını kaydet
add_action( 'wp_enqueue_scripts', 'urun_sayfasi_stilleri' );
function urun_sayfasi_stilleri() {
// Sadece tekil ürün sayfalarında yükle
if ( is_product() ) {
wp_add_inline_style( 'woocommerce-general', '
.guven-mesaji {
background: #f0f8ff;
border-left: 4px solid #0073aa;
padding: 15px 20px;
margin: 20px 0;
border-radius: 0 4px 4px 0;
}
.stok-uyari.kritik {
background: #fff3cd;
border: 1px solid #ffc107;
padding: 10px 15px;
border-radius: 4px;
margin: 10px 0;
}
.stok-uyari.yeterli {
background: #d4edda;
border: 1px solid #28a745;
padding: 10px 15px;
border-radius: 4px;
margin: 10px 0;
}
.sayfa-sonu-bolumu {
margin-top: 40px;
padding-top: 30px;
border-top: 1px solid #eee;
}
' );
}
}
wp_add_inline_style kullanmak, stil kurallarını mevcut bir CSS dosyasının ardından yerleştirir. woocommerce-general handle’ı WooCommerce’in ana CSS dosyasıdır. Bu sayede gereksiz HTTP isteği oluşturmadan stilleri sayfalara eklersiniz.
Hata Ayıklama ve Yaygın Sorunlar
Bu kod örneklerini uygularken karşılaşılabilecek yaygın sorunlar ve çözümleri:
Hook çalışmıyor görünüyorsa:
is_product()koşulunu kontrol edin, yanlış hook noktası seçmiş olabilirsiniz- Öncelik numarasını değiştirin, başka eklentiler aynı hook’ta çalışıyor olabilir
var_dumpile hook’un tetiklendiğini doğrulayın
$product nesnesi null dönüyorsa:
add_action( 'woocommerce_after_single_product_summary', 'guvenli_urun_kontrolu', 10 );
function guvenli_urun_kontrolu() {
// Global product nesnesini güvenli şekilde al
if ( ! function_exists( 'wc_get_product' ) ) {
return;
}
$product_id = get_the_ID();
if ( ! $product_id ) {
return;
}
$product = wc_get_product( $product_id );
if ( ! $product || ! $product->is_type( 'simple', 'variable', 'grouped', 'external' ) ) {
return;
}
// Güvenli içerik çıktısı
echo '<p>Ürün ID: ' . intval( $product->get_id() ) . '</p>';
}
Tema güncellemesi sonrası kayıp problemi: Tüm bu kodları child tema functions.php dosyasına yazın. Ana tema functions.php’sine yazdığınız kodlar tema güncellendiğinde silinir. Child tema yoksa ve oluşturmak zahmetli geliyorsa, en azından küçük bir “site özelleştirme” eklentisi oluşturun.
Performans Optimizasyonu
Her hook callback’i sadece ürün sayfalarında çalışmalıdır. Aksi halde WordPress her sayfa yüklenişinde bu fonksiyonları çalıştırmaya çalışır.
add_action( 'template_redirect', 'kosullu_hook_kaydi' );
function kosullu_hook_kaydi() {
// Sadece tekil ürün sayfalarında hook'ları kaydet
if ( ! is_product() ) {
return;
}
add_action( 'woocommerce_after_single_product_summary', 'agir_hesaplama_gerektiren_icerik', 20 );
add_action( 'woocommerce_after_single_product', 'sayfa_sonu_bolumu', 10 );
}
function agir_hesaplama_gerektiren_icerik() {
// Transient cache kullanarak veritabanı sorgularını azalt
$product_id = get_the_ID();
$cache_key = 'ozel_icerik_' . $product_id;
$cached_content = get_transient( $cache_key );
if ( false === $cached_content ) {
// Pahalı hesaplamayı yap
$cached_content = '<p>Hesaplanan özel içerik buraya gelir.</p>';
// 1 saat boyunca önbelle
set_transient( $cache_key, $cached_content, HOUR_IN_SECONDS );
}
echo wp_kses_post( $cached_content );
}
template_redirect hook’u sayfa şablonu belirlendiğinde tetiklenir ve koşullu etiketlerin çalışması için güvenli bir noktadır. Bu yaklaşım, hook’ları global olarak kaydetmek yerine sadece gerektiğinde devreye sokar.
Çok Dilli Sitelerde İçerik Yönetimi
WPML veya Polylang kullanan sitelerde hook’larla eklenen içeriklerin çeviri desteği önemlidir.
add_action( 'woocommerce_after_single_product', 'cok_dilli_icerik_ekle', 10 );
function cok_dilli_icerik_ekle() {
// WordPress __() ve _e() fonksiyonlarını kullan
$metin_baslik = __( 'Güvenli Alışveriş Garantisi', 'tema-text-domain' );
$metin_icerik = __( 'Tüm ödemeleriniz SSL ile şifrelenmektedir.', 'tema-text-domain' );
echo '<div class="guvenli-alisveris">';
echo '<h3>' . esc_html( $metin_baslik ) . '</h3>';
echo '<p>' . esc_html( $metin_icerik ) . '</p>';
echo '</div>';
}
__() fonksiyonu çeviriyi string olarak döndürür, _e() ise doğrudan ekrana basar. Text domain parametresi (tema-text-domain) temanızın style.css dosyasında tanımladığınız Text Domain değeriyle eşleşmelidir.
Gerçek Dünya Senaryosu: Kampanya Bandı Entegrasyonu
Son olarak, gerçek bir e-ticaret projesinde sık karşılaşılan senaryoyu ele alalım. Belirli bir tarih aralığında aktif olan kampanyaları ürün sayfalarının sonunda göstermek:
add_action( 'woocommerce_after_single_product_summary', 'aktif_kampanya_goster', 25 );
function aktif_kampanya_goster() {
$simdi = current_time( 'timestamp' );
$kampanya_bas = strtotime( '2024-12-20 00:00:00' );
$kampanya_bit = strtotime( '2024-12-31 23:59:59' );
// Kampanya aktif mi?
if ( $simdi < $kampanya_bas || $simdi > $kampanya_bit ) {
return;
}
global $product;
if ( ! $product ) {
$product = wc_get_product( get_the_ID() );
}
// Sadece indirimli olmayan ürünlerde göster
if ( $product->is_on_sale() ) {
return;
}
$kalan_sure = $kampanya_bit - $simdi;
$kalan_gun = floor( $kalan_sure / DAY_IN_SECONDS );
echo '<div class="kampanya-bandi">';
echo '<p>🎄 Yılbaşı indirimi başladı! Kuponu kullanın: <strong>YILBASI2024</strong>';
if ( $kalan_gun > 0 ) {
echo ' - Kampanya ' . intval( $kalan_gun ) . ' gün sonra sona eriyor.';
} else {
echo ' - Kampanya bugün sona eriyor!';
}
echo '</p>';
echo '</div>';
}
Bu örnekte DAY_IN_SECONDS WordPress’in tanımladığı bir sabit olup 86400 değerine eşittir. Benzer şekilde HOUR_IN_SECONDS, WEEK_IN_SECONDS ve MONTH_IN_SECONDS sabitleri de mevcuttur.
Sonuç
WooCommerce ürün sayfasının sonuna içerik eklemek, doğru hook’ları bilmek ve güvenli kod yazmak üzerine kuruludur. woocommerce_after_single_product_summary günlük işler için, woocommerce_after_single_product ise sayfanın gerçek sonunu hedeflediğinizde tercih edilecek hook’tur.
Kritik noktalara bakalım:
- Her zaman
esc_html(),esc_url()veyawp_kses_post()kullanın: Veritabanından veya kullanıcıdan gelen verileri doğrudan ekrana basmayın is_product()koşulunu kullanın: Hook’larınız sadece gerekli sayfalarda çalışsın- Child tema kullanın: Ana tema functions.php’si güncellemeler sırasında sıfırlanır
- Transient cache ekleyin: Veritabanı sorgusu içeren fonksiyonları önbelleğe alın
- Öncelik numaralarına dikkat edin: Başka eklentilerle çakışma olduğunda öncelik parametresiyle sıralamayı kontrol edin
Bu yaklaşımlar, ürün sayfanızı zenginleştirirken sitenizin performansını ve güvenliğini korumanızı sağlar. Eklediğiniz her yeni hook callback’ini staging ortamında test etmek, canlı sitede sürprizlerle karşılaşmamak için en iyi alışkanlıktır.
