WooCommerce Ürün Başlığını Programatik Olarak Değiştirme
E-ticaret sitelerinde ürün başlıklarını dinamik olarak değiştirme ihtiyacı, aslında çok daha yaygın bir senaryo. Düşün bir kere: sezonluk kampanyalar, toplu başlık güncellemeleri, SEO optimizasyonları ya da kullanıcı bazlı kişiselleştirmeler. Bunların hepsini WooCommerce arayüzünden tek tek yapmak hem yorucu hem de hata yaratmaya açık. İşte tam burada WordPress’in hook sistemi ve WooCommerce’in API fonksiyonları devreye giriyor. functions.php dosyasına yazacağın birkaç satır kod, saatlerce sürecek manuel işi dakikalara indirebilir.
Temel Mantığı Anlamak
WooCommerce’de bir ürün başlığını programatik olarak değiştirmenin iki temel yolu var. Birincisi kalıcı değişiklik: ürün verisini veritabanında güncellersin, başlık sonsuza dek değişir. İkincisi dinamik değişiklik: başlık veritabanında aynı kalır ama kullanıcıya gösterilen metin bir filter hook üzerinden modifiye edilir, geçici ve koşullu değişiklikler için idealdir.
Bu iki yaklaşımın farkını kavramak kritik. Kalıcı değişiklikte wp_update_post() veya WooCommerce’in kendi WC_Product metodlarını kullanırsın. Dinamik değişiklikte ise the_title veya woocommerce_product_title gibi filtreleri hook’larsın. Hangisinin ne zaman kullanılacağını bilmek, iyi bir sysadmin ile iyi bir WordPress geliştiricisini birbirinden ayıran şeylerden biri.
Filter Hook ile Dinamik Başlık Değişikliği
En hızlı ve geri alınabilir yöntemden başlayalım. the_title filtresi, WordPress genelinde her başlık yazdırıldığında tetiklenir. Ama dikkatli olmak lazım çünkü bu hook sadece ürünleri değil, tüm post tiplerini etkiler.
// functions.php
add_filter('the_title', 'custom_product_title_modifier', 10, 2);
function custom_product_title_modifier($title, $post_id) {
// Sadece WooCommerce ürünlerini hedef al
if (get_post_type($post_id) !== 'product') {
return $title;
}
// Ürün nesnesini al
$product = wc_get_product($post_id);
if (!$product) {
return $title;
}
// Stokta olmayan ürünlere etiket ekle
if (!$product->is_in_stock()) {
return $title . ' [Stok Dışı]';
}
return $title;
}
Bu basit örnek, stokta olmayan ürünlerin başlığına otomatik olarak [Stok Dışı] etiketi ekliyor. Veritabanına hiçbir şey yazılmıyor, filtre sadece render anında çalışıyor.
Belirli Bir Ürünün Başlığını Kalıcı Olarak Değiştirme
Bazen belirli bir ürünün başlığını programatik olarak güncellemen gerekir. Bir migration scripti yazıyorsun, eski bir sistemi aktarıyorsun ya da toplu bir değişiklik yapacaksın. Bu durumda wp_update_post() en sağlam yol.
// Tek bir ürünün başlığını güncelle
function update_single_product_title($product_id, $new_title) {
// Önce ürünün gerçekten var olduğunu doğrula
$product = wc_get_product($product_id);
if (!$product) {
error_log("Ürün bulunamadı: ID " . $product_id);
return false;
}
$result = wp_update_post(array(
'ID' => $product_id,
'post_title' => sanitize_text_field($new_title),
'post_name' => sanitize_title($new_title) // Slug da güncellenir
));
if (is_wp_error($result)) {
error_log("Başlık güncellenemedi: " . $result->get_error_message());
return false;
}
// WooCommerce önbelleğini temizle
wc_delete_product_transients($product_id);
clean_post_cache($product_id);
return true;
}
// Kullanım örneği
// update_single_product_title(42, 'Yeni Ürün Adı 2024');
Burada dikkat edilmesi gereken birkaç nokta var. sanitize_text_field() kullanmak güvenlik açısından şart. post_name yani slug’ı da güncellersen SEO için 301 yönlendirme yapmayı unutma. Ve her değişiklikten sonra transient’leri temizlemek, önbellek kaynaklı sorunların önüne geçer.
WC_Product Metodlarıyla Daha Güvenli Güncelleme
WooCommerce’in kendi OOP yapısını kullanmak, wp_update_post() yerine daha tercih edilen bir yöntem. Özellikle WooCommerce’e özgü metadata ile birlikte çalışırken bu yaklaşım çok daha temiz sonuç veriyor.
// WC_Product nesnesi üzerinden başlık güncelleme
function update_product_title_via_wc($product_id, $new_title) {
$product = wc_get_product($product_id);
if (!$product) {
return new WP_Error('invalid_product', 'Geçersiz ürün ID: ' . $product_id);
}
// Başlığı set et
$product->set_name(sanitize_text_field($new_title));
// Değişiklikleri kaydet
$saved_id = $product->save();
if (!$saved_id) {
return new WP_Error('save_failed', 'Ürün kaydedilemedi.');
}
// Obje önbelleğini de temizle
wp_cache_delete($product_id, 'posts');
wc_delete_product_transients($product_id);
return $saved_id;
}
set_name() metodu WooCommerce 3.0 ile geldi ve post_title alanını günceller. Bu yöntemi kullandığında WooCommerce’in kendi hook’ları da düzgün şekilde tetikleniyor, yani bir eklenti ürün güncellemelerini dinliyorsa haberdar olacak.
Toplu Başlık Güncelleme Senaryosu
Gerçek dünya senaryosu: 500 ürünlük bir katalogda tüm ürün başlıklarına marka adını eklemen gerekiyor. Ya da bir CSV dosyasından okunan yeni başlıklarla mevcut ürünleri güncelliyorsun. Böyle bir durumda döngü içinde dikkatli olmak lazım, aksi halde sunucu kaynakları yorulabilir.
// Toplu ürün başlığı güncelleme - bellek dostu yaklaşım
function bulk_update_product_titles($updates_array, $batch_size = 50) {
$total = count($updates_array);
$updated = 0;
$failed = 0;
$log = array();
// Büyük veri setlerini parçalara böl
$batches = array_chunk($updates_array, $batch_size, true);
foreach ($batches as $batch) {
foreach ($batch as $product_id => $new_title) {
$product = wc_get_product($product_id);
if (!$product) {
$failed++;
$log[] = "HATA - ID {$product_id}: Ürün bulunamadı";
continue;
}
$old_title = $product->get_name();
$product->set_name(sanitize_text_field($new_title));
if ($product->save()) {
$updated++;
$log[] = "OK - ID {$product_id}: '{$old_title}' >> '{$new_title}'";
wc_delete_product_transients($product_id);
} else {
$failed++;
$log[] = "HATA - ID {$product_id}: Kayıt başarısız";
}
}
// Her batch sonrası belleği temizle
// Büyük sitelerde kritik!
wp_cache_flush();
}
// Sonuç raporu
$summary = array(
'total' => $total,
'updated' => $updated,
'failed' => $failed,
'log' => $log
);
// Log dosyasına yaz
error_log(print_r($summary, true));
return $summary;
}
// Kullanım örneği:
// $data = array(
// 42 => 'Yeni Başlık Ürün 1',
// 87 => 'Yeni Başlık Ürün 2',
// 156 => 'Yeni Başlık Ürün 3',
// );
// bulk_update_product_titles($data, 25);
Bu fonksiyonda array_chunk() kullanımına dikkat et. 500 ürünü tek seferde işlemeye kalkışırsan PHP memory limit’e çarpabilirsin. 25-50’lik batch’ler halinde işlemek hem hafıza hem de performans açısından çok daha sağlıklı.
Koşullu ve Dinamik Başlık Değişiklikleri
Bazen başlığı sadece belirli koşullarda değiştirmek istersin. Örneğin kampanya dönemlerinde, belirli kullanıcı rollerine özel gösterimler ya da stok durumuna göre dinamik başlıklar bunların arasında sayılabilir.
// Kampanya dönemine göre dinamik başlık
add_filter('woocommerce_product_title', 'seasonal_product_title', 10, 2);
function seasonal_product_title($title, $product) {
$current_month = (int) date('n');
$product_id = $product->get_id();
// Belirli kategorideki ürünlere kampanya etiketi ekle
$campaign_categories = array('indirimli-urunler', 'yazlik-koleksiyon');
if (has_term($campaign_categories, 'product_cat', $product_id)) {
// Yaz kampanyası (Haziran - Ağustos)
if ($current_month >= 6 && $current_month <= 8) {
return '🌞 ' . $title . ' - Yaz İndirimi';
}
// Kış kampanyası (Aralık - Şubat)
if ($current_month == 12 || $current_month <= 2) {
return '❄️ ' . $title . ' - Kış Fırsatı';
}
}
// Yeni ürünler (son 30 gün içinde eklenmiş)
$date_created = $product->get_date_created();
if ($date_created) {
$days_old = (time() - $date_created->getTimestamp()) / DAY_IN_SECONDS;
if ($days_old <= 30) {
return '🆕 ' . $title;
}
}
return $title;
}
woocommerce_product_title filtresi, the_title‘a göre daha spesifik. İkinci parametre olarak doğrudan $product nesnesini alıyorsun, yani ürüne ait tüm verilere kolayca ulaşabiliyorsun.
Kullanıcı Rolüne Göre Başlık Değiştirme
B2B e-ticaret sitelerinde sık karşılaşılan bir senaryo: toptancılara ve perakendecilere aynı ürün için farklı başlıklar göstermek. Bazen başlığa asgari sipariş miktarı, özel fiyat bilgisi ya da müşteri kategorisi eklenir.
// Kullanıcı rolüne göre ürün başlığı kişiselleştirme
add_filter('the_title', 'role_based_product_title', 10, 2);
function role_based_product_title($title, $post_id) {
// Sadece ürün sayfalarında ve arşiv sayfalarında çalış
if (!is_product() && !is_shop() && !is_product_category()) {
return $title;
}
if (get_post_type($post_id) !== 'product') {
return $title;
}
// Kullanıcı giriş yapmamışsa normal başlığı döndür
if (!is_user_logged_in()) {
return $title;
}
$current_user = wp_get_current_user();
$user_roles = (array) $current_user->roles;
// Toptancı rolü için özel başlık
if (in_array('wholesaler', $user_roles)) {
$product = wc_get_product($post_id);
if ($product) {
$min_qty = get_post_meta($post_id, '_minimum_order_quantity', true);
if ($min_qty && $min_qty > 1) {
return $title . ' (Min. ' . $min_qty . ' Adet)';
}
}
}
// VIP müşteriler için özel etiket
if (in_array('vip_customer', $user_roles)) {
return '⭐ ' . $title;
}
return $title;
}
WP-CLI ile Toplu Başlık Güncelleme
Komut satırından çalışmayı seven sysadmin’ler için WP-CLI üzerinden toplu güncelleme yapmak çok daha pratik. Özellikle SSH erişimin varsa ve büyük bir veritabanıyla uğraşıyorsan, PHP timeout sorunlarını atlayabilirsin.
# WP-CLI ile belirli bir ürünün başlığını güncelle
wp post update 42 --post_title="Yeni Ürün Başlığı" --allow-root
# Belirli bir kategorideki tüm ürünleri listele
wp post list --post_type=product --fields=ID,post_title --format=csv
# CSV dosyasından toplu güncelleme için özel komut
# Önce update-titles.php dosyasını oluştur:
cat > /tmp/update-titles.php << 'EOF'
<?php
$updates = array(
42 => 'Başlık Bir',
87 => 'Başlık İki',
156 => 'Başlık Üç',
);
foreach ($updates as $id => $title) {
$product = wc_get_product($id);
if ($product) {
$product->set_name($title);
$product->save();
WP_CLI::success("ID {$id} güncellendi: {$title}");
} else {
WP_CLI::error("ID {$id} bulunamadı", false);
}
}
EOF
# Sonra WP-CLI ile çalıştır
wp eval-file /tmp/update-titles.php --allow-root
WP-CLI’nın güzel tarafı script’i WordPress ortamında çalıştırıyor ama HTTP request overhead’i olmadan. Büyük toplu işlemler için bu yöntemi kesinlikle tavsiye ederim.
Sık Yapılan Hatalar ve Çözümleri
Pratikte en çok karşılaşılan sorunlardan bahsedelim.
Sonsuz döngü problemi: save_post hook’unu kullanarak başlık güncellemeye çalışırsan ve bu hook içinde tekrar wp_update_post() çağırırsan sonsuz döngüye girersin. Bunu engellemek için:
// save_post hook'unda sonsuz döngüyü önleme
add_action('save_post', 'prevent_loop_product_title_update', 10, 3);
function prevent_loop_product_title_update($post_id, $post, $update) {
// Otomatik kayıtları atla
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
// Sadece ürünler için çalış
if ($post->post_type !== 'product') {
return;
}
// Hook'u geçici olarak kaldır - sonsuz döngü engeli
remove_action('save_post', 'prevent_loop_product_title_update', 10);
// Başlık manipülasyonu yap
$modified_title = strtoupper($post->post_title); // Örnek işlem
wp_update_post(array(
'ID' => $post_id,
'post_title' => $modified_title,
));
// Hook'u geri ekle
add_action('save_post', 'prevent_loop_product_title_update', 10, 3);
}
Önbellek sorunları: Başlığı güncelledikten sonra değişikliğin görünmemesi en yaygın şikayetlerden biri. Bunun için kapsamlı bir önbellek temizleme fonksiyonu işe yarar:
// Kapsamlı önbellek temizleme
function flush_product_cache($product_id) {
// WordPress obje önbelleği
clean_post_cache($product_id);
wp_cache_delete($product_id, 'posts');
wp_cache_delete($product_id, 'post_meta');
// WooCommerce transient'leri
wc_delete_product_transients($product_id);
// WooCommerce obje önbelleği (WC 3.9+)
if (function_exists('WC') && WC()->cache_helper) {
WC()->cache_helper->invalidate_cache_group('product_' . $product_id);
}
// Eğer WP Rocket, W3TC gibi bir önbellek eklentisi varsa
if (function_exists('rocket_clean_post')) {
rocket_clean_post($product_id); // WP Rocket
}
if (function_exists('w3tc_flush_post')) {
w3tc_flush_post($product_id); // W3 Total Cache
}
}
Performans İpuçları
Büyük kataloglarda başlık değişikliklerini yaparken şunlara dikkat etmek gerekiyor.
wc_get_product()yerineget_post(): Eğer sadece başlığa erişmen gerekiyorsa ve WooCommerce’e özgü veri okuman gerekmiyorsaget_post($id)->post_titleçok daha hafif bir çağrı.- Transient önbelleğe alma: Dinamik başlık hesaplamaları yapıyorsan sonuçları
set_transient()ile önbelleğe al, her sayfa yüklemesinde hesaplama yapma. wp_suspend_cache_invalidation(): Toplu güncellemelerde önbellek invalidasyon’unu geçici olarak askıya almak işlemi hızlandırır. Güncelleme bittikten sonra bir kere toplu temizle.- Direct query kullanımı: Acil durumlarda ve
$wpdbüzerinden direkt SQL ile başlık güncellemesi yapmak mümkün ama WooCommerce hook’larını atlayacağı için dikkatli olmak lazım. - WP-CLI kullanımı: PHP max execution time sorunlarını bypass etmek için büyük işlemleri her zaman WP-CLI üzerinden çalıştır.
Güvenlik Kontrolleri
Başlık güncelleme fonksiyonlarına dışarıdan erişim olasılığına karşı her zaman nonce ve capability kontrolleri ekle.
// Admin AJAX üzerinden güvenli başlık güncelleme
add_action('wp_ajax_update_product_title', 'ajax_update_product_title');
function ajax_update_product_title() {
// Nonce doğrulaması
if (!check_ajax_referer('product_title_nonce', 'nonce', false)) {
wp_send_json_error('Geçersiz güvenlik tokeni.');
return;
}
// Yetki kontrolü
if (!current_user_can('edit_products')) {
wp_send_json_error('Bu işlem için yetkiniz yok.');
return;
}
$product_id = absint($_POST['product_id']);
$new_title = sanitize_text_field($_POST['new_title']);
if (empty($new_title)) {
wp_send_json_error('Başlık boş olamaz.');
return;
}
$product = wc_get_product($product_id);
if (!$product) {
wp_send_json_error('Ürün bulunamadı.');
return;
}
$product->set_name($new_title);
$saved = $product->save();
if ($saved) {
wc_delete_product_transients($product_id);
wp_send_json_success(array(
'message' => 'Başlık güncellendi.',
'new_title' => $new_title,
));
} else {
wp_send_json_error('Kayıt sırasında hata oluştu.');
}
}
Sonuç
WooCommerce’de ürün başlıklarını programatik olarak değiştirmek kulağa basit geliyor ama doğru yaklaşımı seçmek, önbellek yönetimini iyi yapmak ve güvenlik kontrollerini atlamak bu işin ince tarafları. Kalıcı değişiklikler için WC_Product::set_name() + save() kombinasyonu en temiz yol. Geçici, koşullu değişiklikler için the_title veya woocommerce_product_title filtreleri yeterli.
Toplu işlemlerde WP-CLI hayat kurtarıcı ve bu konuda zaman harcamaya değer. Batch processing, önbellek yönetimi ve hata loglama mekanizmalarını baştan doğru kurarsanı ilerleyen süreçte çok daha az baş ağrısı çekersin. Kodları doğrudan production’a atmak yerine staging ortamında test etmek de ayrı bir hatırlatma olarak ekleyeyim. Büyük kataloglarda bir hata 500 ürünün başlığını mahvedebilir ve o veriyi geri almak için ya bir backup’a ya da WP-CLI sihirbazlığına ihtiyaç duyarsın.
