WooCommerce CLI ile Çoklu Dil Ürün Yönetimi
Çok dilli bir WooCommerce mağazası yönetmek, özellikle yüzlerce ürün söz konusu olduğunda, admin panelinden tek tek çalışmayı adeta işkenceye dönüştürebilir. WPML veya Polylang gibi eklentilerle entegre çalışan WP-CLI komutları, bu süreci dramatik biçimde hızlandırıyor. Bu yazıda, WooCommerce CLI araçlarını kullanarak çoklu dil ürün yönetimini nasıl otomatize edebileceğinizi, gerçek dünya senaryolarıyla birlikte ele alacağız.
Neden CLI ile Çoklu Dil Yönetimi?
Admin panelinden ürün çevirisi eklemek, özellikle toplu işlemlerde son derece verimsiz. Diyelim ki 500 ürününüz var ve her birine Almanca, Fransızca, İspanyolca çeviri eklemeniz gerekiyor. Bu işlemi panelden yapmaya kalkışırsanız günlerinizi harcarsınız. WP-CLI bu noktada devreye giriyor.
WP-CLI’nin asıl gücü, betiklerle birleştiğinde ortaya çıkıyor. CSV’den veri okuyup toplu ürün oluşturabilir, mevcut ürünleri güncelleyebilir ve dil meta verilerini programatik olarak yönetebilirsiniz. Üstelik SSH üzerinden uzak sunucuda çalıştırabildiğiniz için yerel geliştirme ortamınızdan doğrudan production’a müdahale etmek de mümkün.
Temel Yapıyı Anlamak
WPML kullandığınızda, WooCommerce ürünleri aslında WordPress post’larıdır ve her dilin çevirisi ayrı bir post kaydı olarak tutulur. icl_translations tablosu bu ilişkiyi yönetir. Polylang ise benzer bir yaklaşımla pll_translations meta verilerini kullanır.
WP-CLI komutlarını çalıştırmadan önce hangi dillerin kurulu olduğunu görmek iyi bir başlangıç noktasıdır.
# WPML kurulu dilleri listele
wp eval 'global $sitepress; print_r($sitepress->get_active_languages());'
# Polylang ile kurulu dilleri listele
wp eval 'print_r(pll_languages_list(array("fields" => "all")));'
# WordPress'te kayıtlı dilleri görmek için
wp language core list --status=installed
Bu komutları çalıştırdıktan sonra elinizde hangi dil kodlarının aktif olduğuna dair net bir tablo çıkar. Türkçe için tr, İngilizce için en, Almanca için de gibi ISO kodlarını not alın, çünkü bunları ileride sık kullanacaksınız.
WooCommerce Ürün Oluşturma Temelleri
Çok dilli yapıya geçmeden önce, temel WooCommerce CLI komutlarını hatırlayalım.
# Basit bir ürün oluştur
wp wc product create
--name="Leather Wallet"
--type=simple
--regular_price=49.99
--description="Handcrafted genuine leather wallet"
--status=publish
--user=admin
# Ürünü belirli bir ID ile sorgula
wp wc product get 123 --user=admin
# Mevcut ürünleri listele
wp wc product list --fields=id,name,status --format=json --user=admin
--user=admin parametresini her komuta eklemeyi alışkanlık haline getirin. WP-CLI, WooCommerce işlemleri için yetki kontrolü yapar ve bu parametre olmadan bazı komutlar hata verebilir.
WPML ile Çoklu Dil Ürün Ekleme
WPML kullandığınız bir senaryoda, ana dilde ürün oluşturduktan sonra diğer diller için çevirileri PHP evaluation komutuyla eklemeniz gerekiyor. WP CLI’nin doğrudan WPML entegrasyonu sınırlı olduğundan wp eval ve wp eval-file burada kritik öneme sahip.
# Ana dilde (Türkçe - orijinal) ürün oluştur
wp wc product create
--name="Deri Cüzdan"
--type=simple
--regular_price=299.90
--description="El yapımı gerçek deri cüzdan, özel dikişli."
--short_description="Hakiki deri, dayanıklı tasarım."
--status=publish
--user=admin
# Oluşturulan ürünün ID'sini al (örneğin 456 geldi)
PRODUCT_ID=456
# WPML ile İngilizce çeviri bağlantısı kur
wp eval "
global $sitepress;
$trid = $sitepress->get_element_trid($PRODUCT_ID, 'post_product');
echo 'TRID: ' . $trid;
"
Şimdi asıl işe gelelim: İngilizce çeviriyi oluşturup WPML’e kaydetmek.
# İngilizce çeviriyi oluşturan PHP dosyası hazırla
cat > /tmp/create_translation.php << 'EOF'
<?php
$original_id = intval($args[0]);
$lang = $args[1];
$title = $args[2];
$description = $args[3];
$price = $args[4];
global $sitepress;
// Orijinal ürünün TRID'ini al
$trid = $sitepress->get_element_trid($original_id, 'post_product');
// Yeni post oluştur (çeviri olarak)
$translated_post_id = wp_insert_post(array(
'post_title' => $title,
'post_content' => $description,
'post_status' => 'publish',
'post_type' => 'product',
));
// Fiyat meta verisini ekle
update_post_meta($translated_post_id, '_regular_price', $price);
update_post_meta($translated_post_id, '_price', $price);
// WPML'e dil bilgisini kaydet
$sitepress->set_element_language_details(
$translated_post_id,
'post_product',
$trid,
$lang
);
echo "Çeviri oluşturuldu. Post ID: " . $translated_post_id;
EOF
# Scripti çalıştır
wp eval-file /tmp/create_translation.php 456 en "Leather Wallet" "Handcrafted genuine leather wallet with special stitching." 19.99 --user=admin
Bu yaklaşım, WPML’in dahili mekanizmasını doğrudan kullandığı için dil ilişkilendirmeleri sağlıklı şekilde kurulur.
Polylang ile Çeviri Yönetimi
Polylang kullananlar için süreç biraz daha doğrudan. Polylang’ın WP-CLI entegrasyonu polylang-cli eklentisiyle genişletilebilir, ancak onu kurmadan da temel işlemleri yapabilirsiniz.
# Polylang ile ürünün dilini sorgula
wp eval "
$post_id = 789;
echo pll_get_post_language($post_id);
"
# Ürüne dil ata (Türkçe)
wp eval "pll_set_post_language(789, 'tr');"
# İki çeviriyi birbirine bağla
wp eval "
$tr_id = 789;
$en_id = 790;
pll_save_post_translations(array('tr' => $tr_id, 'en' => $en_id));
echo 'Çeviriler bağlandı.';
"
Polylang’da önemli bir nokta: pll_save_post_translations fonksiyonu tüm dilleri içeren bir array bekler. Eksik dil bırakırsanız mevcut bağlantıları bozabilirsiniz. Bu yüzden önce mevcut çevirileri alıp üzerine ekleme yapın.
# Mevcut çevirileri alıp yenisini ekle
wp eval "
$post_id = 789;
$existing = pll_get_post_translations($post_id);
$existing['de'] = 800; // Almanca çeviri ID
pll_save_post_translations($existing);
echo 'Almanca çeviri eklendi.';
"
Toplu CSV’den Çok Dilli Ürün İçe Aktarma
Gerçek dünyada en sık karşılaşılan senaryo budur: Bir CSV dosyanız var, içinde Türkçe ve İngilizce ürün bilgileri var, bunları sisteme aktarmanız gerekiyor.
Örnek CSV yapısı şöyle olsun:
- tr_name: Türkçe ürün adı
- en_name: İngilizce ürün adı
- tr_description: Türkçe açıklama
- en_description: İngilizce açıklama
- price: Fiyat (TL)
- sku: Stok kodu
# Toplu içe aktarma scripti
cat > /tmp/bulk_multilang_import.php << 'EOF'
<?php
$csv_file = $args[0];
$handle = fopen($csv_file, 'r');
$header = fgetcsv($handle);
global $sitepress;
while (($row = fgetcsv($handle)) !== false) {
$data = array_combine($header, $row);
// Türkçe ürün oluştur (ana dil)
$tr_id = wp_insert_post(array(
'post_title' => $data['tr_name'],
'post_content' => $data['tr_description'],
'post_status' => 'publish',
'post_type' => 'product',
));
// Meta verileri ekle
update_post_meta($tr_id, '_regular_price', $data['price']);
update_post_meta($tr_id, '_price', $data['price']);
update_post_meta($tr_id, '_sku', $data['sku']);
update_post_meta($tr_id, '_manage_stock', 'no');
// WPML'e Türkçe olarak kaydet
$trid = $sitepress->get_element_trid($tr_id, 'post_product');
$sitepress->set_element_language_details($tr_id, 'post_product', $trid, 'tr', true);
// İngilizce çeviri oluştur
$en_id = wp_insert_post(array(
'post_title' => $data['en_name'],
'post_content' => $data['en_description'],
'post_status' => 'publish',
'post_type' => 'product',
));
update_post_meta($en_id, '_regular_price', $data['price']);
update_post_meta($en_id, '_price', $data['price']);
update_post_meta($en_id, '_sku', $data['sku'] . '-en');
// İngilizce olarak kaydet ve Türkçeyle ilişkilendir
$sitepress->set_element_language_details($en_id, 'post_product', $trid, 'en');
WP_CLI::success("Ürün oluşturuldu: {$data['tr_name']} (TR: $tr_id, EN: $en_id)");
}
fclose($handle);
WP_CLI::success("Tüm ürünler içe aktarıldı.");
EOF
wp eval-file /tmp/bulk_multilang_import.php /var/www/products.csv --user=admin
Bu script çalışırken her ürün için başarı mesajı göreceksiniz, böylece hangi noktada sorun çıktığını anlık takip edebilirsiniz.
Mevcut Ürünlere Toplu Çeviri Ekleme
Daha yaygın bir senaryo şu: Elinizde zaten binlerce Türkçe ürün var ve şimdi İngilizce pazara açılmak istiyorsunuz. Tüm bu ürünlere İngilizce çeviri atamanız gerekiyor.
# Çevirisi olmayan ürünleri bul
wp eval "
global $wpdb;
$results = $wpdb->get_results("
SELECT p.ID, p.post_title
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->prefix}icl_translations t
ON t.element_id = p.ID AND t.element_type = 'post_product'
WHERE p.post_type = 'product'
AND p.post_status = 'publish'
AND t.element_id IS NULL
LIMIT 20
");
foreach($results as $r) {
echo $r->ID . ' - ' . $r->post_title . PHP_EOL;
}
"
Çevirisi eksik ürünleri tespit ettikten sonra, bunları otomatik olarak işleyebilecek bir betik yazabilirsiniz. Gerçek bir projede bu çeviriler genellikle bir çeviri servisinden gelir ve JSON formatında teslim edilir.
# JSON formatındaki çevirileri içe aktar
cat > /tmp/apply_translations.php << 'EOF'
<?php
$json_file = $args[0];
$target_lang = $args[1];
$translations = json_decode(file_get_contents($json_file), true);
global $sitepress;
foreach ($translations as $item) {
$original_id = $item['original_id'];
$translated_title = $item['title'];
$translated_content = $item['content'];
// Mevcut çeviri var mı kontrol et
$trid = $sitepress->get_element_trid($original_id, 'post_product');
$existing = $sitepress->get_element_translations($trid);
if (isset($existing[$target_lang])) {
// Mevcut çeviriyi güncelle
$trans_id = $existing[$target_lang]->element_id;
wp_update_post(array(
'ID' => $trans_id,
'post_title' => $translated_title,
'post_content' => $translated_content,
));
WP_CLI::line("Güncellendi (ID: $trans_id): $translated_title");
} else {
// Yeni çeviri oluştur
$trans_id = wp_insert_post(array(
'post_title' => $translated_title,
'post_content' => $translated_content,
'post_status' => 'publish',
'post_type' => 'product',
));
// Fiyat ve meta verileri kopyala
$price = get_post_meta($original_id, '_regular_price', true);
update_post_meta($trans_id, '_regular_price', $price);
update_post_meta($trans_id, '_price', $price);
$sitepress->set_element_language_details($trans_id, 'post_product', $trid, $target_lang);
WP_CLI::line("Oluşturuldu (ID: $trans_id): $translated_title");
}
}
WP_CLI::success("İşlem tamamlandı. " . count($translations) . " ürün işlendi.");
EOF
wp eval-file /tmp/apply_translations.php /var/www/en_translations.json en --user=admin
Kategori ve Tag Çevirilerini Yönetmek
Ürünleri çevirdikten sonra kategorilerin de çevrilmesi gerektiğini genellikle sonradan fark edersiniz. WPML’de taxonomy çevirileri biraz farklı çalışır.
# Mevcut WooCommerce kategorilerini listele
wp term list product_cat --fields=term_id,name,slug --format=table
# Kategori çevirisi ekle (WPML)
wp eval "
global $sitepress;
$original_term_id = 15; // Türkçe kategori ID
$trid = $sitepress->get_element_trid($original_term_id, 'tax_product_cat');
// İngilizce terimi oluştur
$result = wp_insert_term('Electronics', 'product_cat', array(
'slug' => 'electronics-en',
'description' => 'Electronic products'
));
if (!is_wp_error($result)) {
$en_term_id = $result['term_id'];
$sitepress->set_element_language_details(
$en_term_id,
'tax_product_cat',
$trid,
'en'
);
echo 'Kategori çevirisi oluşturuldu. Term ID: ' . $en_term_id;
} else {
echo 'Hata: ' . $result->get_error_message();
}
"
Ürün Meta Verisi ve Attribute Çevirileri
Ürün özelliklerinin (renk, beden, malzeme gibi) de çevrilmesi gerekir. Bu özellikle giyim, elektronik gibi attribute yoğun sektörlerde kritik öneme sahiptir.
# WooCommerce attribute'lerini listele
wp wc product_attribute list --user=admin
# Attribute değerlerini (terms) listele
wp term list pa_color --fields=term_id,name,slug
# Toplu attribute çevirisi scripti
cat > /tmp/translate_attributes.php << 'EOF'
<?php
$attribute_taxonomy = $args[0]; // örn: pa_color
$lang = $args[1];
global $sitepress;
$terms = get_terms(array(
'taxonomy' => $attribute_taxonomy,
'hide_empty' => false,
'lang' => 'tr' // Ana dil
));
$translations_map = array(
'Kırmızı' => 'Red',
'Mavi' => 'Blue',
'Yeşil' => 'Green',
'Siyah' => 'Black',
'Beyaz' => 'White',
);
foreach ($terms as $term) {
if (isset($translations_map[$term->name])) {
$trid = $sitepress->get_element_trid($term->term_id, 'tax_' . $attribute_taxonomy);
$result = wp_insert_term(
$translations_map[$term->name],
$attribute_taxonomy,
array('slug' => sanitize_title($translations_map[$term->name] . '-' . $lang))
);
if (!is_wp_error($result)) {
$sitepress->set_element_language_details(
$result['term_id'],
'tax_' . $attribute_taxonomy,
$trid,
$lang
);
WP_CLI::success("{$term->name} -> {$translations_map[$term->name]} çevrildi.");
}
}
}
EOF
wp eval-file /tmp/translate_attributes.php pa_color en --user=admin
Dil Tutarlılığını Doğrulama
Tüm bu işlemleri yaptıktan sonra tutarlılığı kontrol etmek şart. Bazı ürünlerin çevirisi eksik kalabilir veya WPML ilişkilendirmeleri hatalı kurulmuş olabilir.
# Çevirisi olmayan Türkçe ürünleri raporla
wp eval "
global $wpdb, $sitepress;
$tr_products = $wpdb->get_results("
SELECT t.element_id, p.post_title
FROM {$wpdb->prefix}icl_translations t
JOIN {$wpdb->posts} p ON p.ID = t.element_id
WHERE t.element_type = 'post_product'
AND t.language_code = 'tr'
AND p.post_status = 'publish'
");
$missing_en = 0;
foreach ($tr_products as $product) {
$trid = $sitepress->get_element_trid($product->element_id, 'post_product');
$translations = $sitepress->get_element_translations($trid);
if (!isset($translations['en'])) {
echo 'EN eksik - ID: ' . $product->element_id . ' - ' . $product->post_title . PHP_EOL;
$missing_en++;
}
}
echo PHP_EOL . 'Toplam eksik İngilizce çeviri: ' . $missing_en;
"
Bu raporu düzenli aralıklarla çalıştırıp bir log dosyasına yazabilirsiniz. Cron job ile günlük otomatik kontrol yapmak, içerik ekibine hangi ürünlerin çevirisinin eksik olduğunu düzenli raporlamanızı sağlar.
# Günlük kontrol için cron job ekle
echo "0 8 * * * www-data wp --path=/var/www/html eval-file /opt/scripts/check_translations.php >> /var/log/wpml_check.log 2>&1" | sudo tee -a /etc/cron.d/wpml-check
Performans Optimizasyonu: Büyük Kataloglarda Çalışmak
Binlerce ürün söz konusu olduğunda, scriptleri küçük batch’ler halinde çalıştırmak şart. Aksi halde PHP memory limiti veya execution timeout sorunlarıyla karşılaşırsınız.
# Batch işleme örneği - her seferinde 50 ürün
cat > /tmp/batch_process.sh << 'EOF'
#!/bin/bash
OFFSET=0
BATCH_SIZE=50
TOTAL=$(wp post list --post_type=product --post_status=publish --format=count --path=/var/www/html)
echo "Toplam ürün: $TOTAL"
while [ $OFFSET -lt $TOTAL ]; do
echo "İşleniyor: $OFFSET - $((OFFSET + BATCH_SIZE))"
wp eval-file /tmp/process_batch.php $OFFSET $BATCH_SIZE
--path=/var/www/html
--user=admin
OFFSET=$((OFFSET + BATCH_SIZE))
sleep 2 # Sunucuya nefes aldır
done
echo "Tüm batch'ler tamamlandı."
EOF
chmod +x /tmp/batch_process.sh
bash /tmp/batch_process.sh
sleep 2 komutunu küçümsemeyin. Büyük işlemlerde sunucuya kısa molalar vermek, MySQL’in sorgu kuyruğunu temizlemesine ve PHP-FPM’in pool’unu toparlamasına olanak tanır. Production ortamında bunu atlamak, site performansını ciddi ölçüde etkileyebilir.
Sık Karşılaşılan Sorunlar ve Çözümleri
WPML dil bilgisi kaydedilmiyor: $sitepress global değişkenine erişemiyorsanız, WPML’in tam olarak yüklendiğinden emin olun. wp eval-file kullanırken WordPress ve tüm eklentiler tam boot oluyor, ama bazen WPML’in dil belirleme mekanizması CLI ortamında farklı davranıyor. Scriptin başına do_action('init') eklemek sorunu çözebilir.
SKU çakışmaları: Çevirileri oluştururken aynı SKU’yu kullanmak sorun çıkarır. Ana dil SKU’sunun sonuna -en, -de gibi suffix ekleyin.
Cache sorunları: Toplu işlem sonrası ürünler admin panelinde güncellenmiş görünmüyorsa WooCommerce cache’ini temizleyin.
# WooCommerce cache temizle
wp cache flush
wp eval "wc_delete_product_transients();"
# WPML cache temizle
wp eval "global $sitepress; $sitepress->reset_cache();"
Memory limit hatası: php.ini üzerinden değişiklik yapamadığınız ortamlarda WP-CLI’nin kendi yapılandırmasını kullanın.
# WP-CLI için memory limitini geçici artır
WP_CLI_PHP_ARGS="-d memory_limit=512M" wp eval-file /tmp/heavy_script.php --user=admin
Sonuç
WP-CLI ile çok dilli WooCommerce yönetimi başlangıçta karmaşık görünebilir, ancak doğru scriptleri bir kez yazdıktan sonra saatlerce sürecek panel işlemlerini dakikalar içinde halledersiniz. Özellikle WPML’in $sitepress API’sini ve Polylang’ın fonksiyonlarını iyi anlamak, sizi güçlü bir konuma taşıyor.
Pratikte en verimli yaklaşım, import scriptlerinizi modüler tutmak ve her projeye özel küçük PHP dosyaları oluşturmak. Bunları versiyon kontrolüne almayı da ihmal etmeyin; ileride benzer bir projeyle karşılaştığınızda hazır bir toolbox’ınız olsun.
Büyük kataloglarda her zaman önce test ortamında deneyin, sonra production’a geçin. WPML ilişkilendirme tablosunda oluşan tutarsızlıkları düzeltmek oldukça can sıkıcı olabilir. Düzenli yedek almak ve işlem öncesi veritabanı snapshot’ı çekmek, gece yarısı paniğini önleyen en basit önlemdir.
