Bir müşteri sipariş verdikten on gün sonra iade talebiyle döndü. Ürünün kişiye özel üretildiğini ve cayma hakkı kapsamı dışında olduğunu söylüyorsunuz; müşteri "ben böyle bir şey okumadım" diyor. WooCommerce panelinde siparişi açıyorsunuz: sipariş satırları var, ödeme bilgisi var, kargo bilgisi var — ama müşterinin hangi metni, hangi tarihte, hangi sürümüyle onayladığına dair tek bir kayıt yok. Üstelik sözleşme metnini geçen ay güncellemiştiniz, dolayısıyla sitede şu an duran metin o siparişin verildiği andaki metin bile değil.
Bu senaryo, mesafeli satışta yasal metinlerin neden "sayfa açıp linki footer'a koymak"tan ibaret olmadığını gösteriyor. Mevzuat sizden yalnızca metni yayımlamanızı değil, tüketiciyi sipariş öncesinde bilgilendirdiğinizi ispat edebilmenizi istiyor. İspat da ancak onayın kaydedilmesiyle ve o andaki metnin saklanmasıyla mümkün.
Bu rehber hukuki bir tanım yazısı değil; WooCommerce üzerinde çalışan bir uygulama rehberi. Ön bilgilendirme formu ile mesafeli satış sözleşmesini ödeme sayfasında ayrı ayrı zorunlu onay kutularıyla göstermeyi, onayı sipariş notuna ve sipariş verisine işlemeyi, metinleri müşteriye e-posta ile iletmeyi ve sipariş anındaki metin sürümünü saklamayı anlatıyorum. Mağazanızı yeni kuruyorsanız önce WooCommerce başlangıç rehberimize göz atın.
Hangi Metinler Gerekli ve Neden İkisi Ayrı Duruyor?#
Türkiye'de mesafeli satışın çerçevesini 6502 sayılı Tüketicinin Korunması Hakkında Kanun ve buna bağlı Mesafeli Sözleşmeler Yönetmeliği çizer. Uygulamada üç ayrı metinle karşılaşırsınız ve bunlar birbirinin yerine geçmez:
| Metin | Ne zaman devreye girer | Temel işlevi |
|---|---|---|
| Ön Bilgilendirme Formu | Sipariş kurulmadan önce | Ürün, fiyat, kargo bedeli, teslimat, cayma hakkı ve satıcı bilgilerini tüketiciye bildirir |
| Mesafeli Satış Sözleşmesi | Sipariş anında kurulur | Tarafların hak ve yükümlülüklerini düzenleyen asıl sözleşme |
| İade ve Değişim Şartları | Sipariş sonrası süreç | Cayma süresi, iade adresi, kargo bedelinin kime ait olduğu, istisnalar |
En sık yapılan hata, üçünü tek bir "Şartlar ve Koşullar" sayfasında birleştirip tek onay kutusuyla geçmektir. Bunun iki sorunu var. Birincisi, ön bilgilendirme formunun siparişten önce ve ayrı olarak sunulması beklenir; sözleşmeyle birleştirildiğinde "önce bilgilendirdim" savunması zayıflar. İkincisi, tüketici uyuşmazlıklarında hakem heyetine sunacağınız kanıt "müşteri şu metni onayladı" değil, "müşteri hangi metni onayladı" sorusunun cevabıdır.
Yönetmelik, ön bilgilendirmenin okunabilir biçimde — en az on iki punto büyüklüğünde, açık ve sade bir dille — sunulmasını ve tüketicinin bu bilgileri edindiğini teyit etmesinin sağlanmasını ister. İşte ödeme sayfasındaki onay kutusu tam olarak bu teyit mekanizmasıdır. Ayrıca satıcı, bilgilendirme ve cayma hakkına ilişkin her işleme dair bilgi ve belgeyi üç yıl saklamakla yükümlüdür. Üç yıl sonra bir uyuşmazlık geldiğinde elinizde bugünkü metin değil, o siparişin metni olmalı.
Metinlerin içeriğini bir hukuk danışmanıyla hazırlamanızı öneririm; bu yazının konusu içerik değil, o içeriğin WooCommerce'te doğru biçimde sunulması ve kanıtlanabilir hâle getirilmesi. Şirket türü, fatura ve vergi tarafındaki yükümlülükler için e-ticaret vergi ve şirket kurulumu yazımız ayrı bir başlangıç noktası.
WooCommerce'in Yerleşik Şartlar Onayı Nerede Ayarlanır?#
WooCommerce kutudan çıktığı hâliyle tek bir sözleşme sayfası desteği sunar. Önce metinlerinizi birer WordPress sayfası olarak oluşturun (/mesafeli-satis-sozlesmesi, /on-bilgilendirme-formu, /iade-ve-degisim), sonra:
WooCommerce → Ayarlar → Gelişmiş → Sayfa kurulumu → Şartlar ve koşullar alanından bir sayfa seçin.
Bu alanı doldurduğunuz anda ödeme sayfasında otomatik olarak "Şartlar ve koşulları okudum, kabul ediyorum" onay kutusu belirir ve işaretlenmeden sipariş tamamlanamaz. Doğrulama sunucu tarafında yapılır, yani tarayıcıdan onay kutusunu kaldırmaya çalışan biri siparişi yine de geçiremez.
Buradaki sınırlama açık: tek sayfa, tek kutu. Ön bilgilendirme formunu ayrı bir onayla göstermek istiyorsanız bunu kendiniz eklemeniz gerekir. Bir de dikkat edilmesi gereken davranış var — bu ayarı doldurduğunuzda WooCommerce, seçilen sayfanın içeriğini ödeme sayfasında kaydırılabilir bir kutunun içinde gösterir. Metin çok uzunsa mobilde kullanışsız olabilir; bu durumda sayfa içeriğini boş bırakıp yalnızca bağlantı gösteren bir yapı tercih edilebilir. Ama unutmayın: metnin görülebilir olması, "okuma imkânı sunuldu" savunmasının bir parçasıdır.
İki Ayrı Onay Kutusunu Klasik Ödeme Sayfasına Eklemek#
Klasik (shortcode tabanlı) ödeme sayfası kullanıyorsanız üç kancayla tam kontrol elde edersiniz: alanı basmak, doğrulamak ve kaydetmek. Aşağıdaki kodu child temanızın functions.php dosyasına veya küçük bir site eklentisine ekleyin — ana temaya yazarsanız ilk güncellemede kaybolur. Child tema kurmadıysanız WordPress child tema yazımıza bakın.
Önce onay kutusunu sipariş verme düğmesinin hemen üstüne basalım:
add_action( 'woocommerce_review_order_before_submit', 'clou_sozlesme_kutulari', 9 );
function clou_sozlesme_kutulari() {
$metinler = array(
'on_bilgilendirme' => array(
'baslik' => 'Ön Bilgilendirme Formu',
'url' => '/on-bilgilendirme-formu/',
),
'mesafeli_satis' => array(
'baslik' => 'Mesafeli Satış Sözleşmesi',
'url' => '/mesafeli-satis-sozlesmesi/',
),
);
foreach ( $metinler as $anahtar => $metin ) {
woocommerce_form_field(
'clou_' . $anahtar,
array(
'type' => 'checkbox',
'class' => array( 'form-row', 'clou-sozlesme' ),
'required' => true,
'label' => sprintf(
'<a href="%s" target="_blank" rel="noopener">%s</a> metnini okudum ve onaylıyorum.',
esc_url( $metin['url'] ),
esc_html( $metin['baslik'] )
),
),
WC()->checkout->get_value( 'clou_' . $anahtar )
);
}
}
Onay kutusunu basmak tek başına yeterli değildir; sunucu tarafında doğrulamazsanız hiçbir hükmü olmaz. Tarayıcıdaki required özniteliği yalnızca bir kolaylıktır ve kolayca atlatılır:
add_action( 'woocommerce_checkout_process', 'clou_sozlesme_dogrula' );
function clou_sozlesme_dogrula() {
if ( empty( $_POST['clou_on_bilgilendirme'] ) ) {
wc_add_notice(
'Siparişi tamamlamak için Ön Bilgilendirme Formunu onaylamanız gerekir.',
'error'
);
}
if ( empty( $_POST['clou_mesafeli_satis'] ) ) {
wc_add_notice(
'Siparişi tamamlamak için Mesafeli Satış Sözleşmesini onaylamanız gerekir.',
'error'
);
}
}
İki kontrolü ayrı yazmak bilinçli bir tercih: müşteri hangi kutuyu atladığını görür, tek bir genel hata mesajıyla baş başa kalmaz. Terk edilen sepetlerin sessiz nedenlerinden biri de anlaşılmayan doğrulama hatalarıdır.
Onayı Sipariş Verisine ve Sipariş Notuna İşlemek#
Buraya kadar müşteri onay verdi ama hiçbir yere yazılmadı. Kanıt değeri olan kısım tam olarak bu adım. İki farklı kancayı birlikte kullanacağız, çünkü görevleri farklı.
woocommerce_checkout_create_order, sipariş nesnesi oluşturulduğunda ama henüz veritabanına yazılmadan önce çalışır — meta verisi eklemek için doğru yer:
add_action( 'woocommerce_checkout_create_order', 'clou_onayi_siparise_yaz', 10, 2 );
function clou_onayi_siparise_yaz( $order, $data ) {
$zaman = current_time( 'mysql' );
$ip = WC_Geolocation::get_ip_address();
$order->update_meta_data( '_clou_on_bilgilendirme_onay', 'evet' );
$order->update_meta_data( '_clou_mesafeli_satis_onay', 'evet' );
$order->update_meta_data( '_clou_sozlesme_onay_zamani', $zaman );
$order->update_meta_data( '_clou_sozlesme_onay_ip', $ip );
}
Sipariş notu ise ancak siparişin kimliği oluştuktan sonra eklenebilir; bu yüzden woocommerce_checkout_order_processed kancasını kullanıyoruz:
add_action( 'woocommerce_checkout_order_processed', 'clou_onay_notu_ekle', 10, 3 );
function clou_onay_notu_ekle( $order_id, $posted_data, $order ) {
$not = sprintf(
"Sözleşme onayları alındı.\nÖn Bilgilendirme Formu: onaylandı\nMesafeli Satış Sözleşmesi: onaylandı\nTarih: %s\nIP: %s",
$order->get_meta( '_clou_sozlesme_onay_zamani' ),
$order->get_meta( '_clou_sozlesme_onay_ip' )
);
// Ikinci parametre false: musteriye gonderilmeyen dahili not
$order->add_order_note( $not, false );
}
Artık siparişi panelde açtığınızda sağ sütundaki not geçmişinde onay kaydını görürsünüz. Meta verisi de siparişe bağlı olduğu için dışa aktarımlarda ve raporlarda taşınır.
Bu kodun $order->update_meta_data() kullanması tesadüf değil. Doğrudan update_post_meta() yazsaydınız, mağazanız yüksek performanslı sipariş depolamaya (HPOS) geçtiğinde bu kayıtlar okunamaz hâle gelirdi — çünkü sipariş artık bir WordPress gönderisi olmaz. Depolama mimarisinin mağaza hızına etkisini WooCommerce performans rehberimizde ele alıyoruz; buradaki kural basit: siparişe ait veriyi her zaman sipariş nesnesi üzerinden yazın ve okuyun.
IP adresi kaydederken kişisel veri işlediğinizi unutmayın; bu işlemenin hukuki dayanağını ve saklama süresini aydınlatma metninizde belirtmelisiniz. KVKK web sitesi uyumu yazımız bu tarafı ele alıyor.
Blok Tabanlı Ödeme Sayfasında Onay Kutusu#
WooCommerce'in yeni blok tabanlı Sepet ve Ödeme blokları, klasik sayfanın kancalarını çalıştırmaz. Ödeme sayfanızı bloklarla kurduysanız yukarıdaki woocommerce_review_order_before_submit yaklaşımı hiçbir şey basmaz — ekranda değişiklik göremezsiniz ve nedenini bulmak zaman alır.
Bloklar için doğru yol, ek ödeme alanları API'sidir. woocommerce_init kancasından sonra bir onay kutusu kaydedersiniz:
add_action( 'woocommerce_init', 'clou_blok_sozlesme_alani' );
function clou_blok_sozlesme_alani() {
if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
return;
}
woocommerce_register_additional_checkout_field( array(
'id' => 'clou/mesafeli-satis',
'label' => 'Mesafeli Satış Sözleşmesini okudum ve onaylıyorum.',
'location' => 'order',
'type' => 'checkbox',
'required' => true,
) );
}
Bu alanın değeri siparişe _wc_other/ önekiyle yazılır; yani clou/mesafeli-satis alanı _wc_other/clou/mesafeli-satis anahtarıyla saklanır. Değeri okumanın önerilen yolu WooCommerce'in kendi yardımcı sınıfıdır:
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
$order = wc_get_order( $order_id );
$fields = Package::container()->get( CheckoutFields::class );
$onay = $fields->get_field_from_object( 'clou/mesafeli-satis', $order, 'other' );
Doğrudan meta okursanız değer boolean değil, "1", "0" veya boş dize olarak gelir — koşul yazarken buna dikkat edin. Ek alanlar API'si göreli olarak yeni olduğundan, blok tabanlı ödeme kullanıyorsanız WooCommerce'i güncel tutmanız gerekir.
Sipariş Anındaki Metni Saklamak: En Çok Atlanan Adım#
Buraya kadar yaptıklarımız "müşteri onayladı" bilgisini kaydeder. Ama kritik soru şudur: neyi onayladı?
Sözleşme metinlerinizi zamanla güncellersiniz — kargo bedeli değişir, iade adresi taşınır, cayma istisnalarına yeni bir ürün grubu eklenir. Altı ay önceki bir siparişle ilgili uyuşmazlıkta sitedeki güncel metni göstermeniz işe yaramaz; hatta aleyhinize sonuç verebilir, çünkü o metin siparişin verildiği anda ortada yoktu.
Çözüm, onay anında metnin kendisini veya en azından sürüm kimliğini siparişe yazmaktır. İki yaklaşım var.
Yaklaşım 1 — Sürüm damgası. Metin sayfasının son değiştirilme tarihini ve içeriğinin özetini (hash) siparişe kaydedersiniz. Hafiftir, veritabanını şişirmez:
add_action( 'woocommerce_checkout_create_order', 'clou_metin_surumu_yaz', 20, 2 );
function clou_metin_surumu_yaz( $order, $data ) {
$sayfalar = array(
'on_bilgilendirme' => get_page_by_path( 'on-bilgilendirme-formu' ),
'mesafeli_satis' => get_page_by_path( 'mesafeli-satis-sozlesmesi' ),
);
foreach ( $sayfalar as $anahtar => $sayfa ) {
if ( ! $sayfa ) {
continue;
}
$order->update_meta_data(
'_clou_' . $anahtar . '_surum',
$sayfa->post_modified . '|' . substr( md5( $sayfa->post_content ), 0, 12 )
);
}
}
Bu yöntem "hangi sürüm onaylandı" sorusuna cevap verir, ama metnin kendisini saklamaz. Sayfayı sonradan silerseniz ya da geçmiş sürümlerini tutmazsanız elinizde yalnızca bir parmak izi kalır.
Yaklaşım 2 — Metni PDF olarak siparişe iliştirmek. Onay anında iki metnin o günkü hâlini PDF'e dönüştürüp siparişe bağlarsınız. En sağlam yöntemdir ve ciddi bir mağazada tercih edilmesi gerekeni budur; ancak PDF üretimi için bir kütüphaneye veya hazır bir eklentiye ihtiyaç duyar.
Pratik bir orta yol: metinlerinizi yayımladığınız her sürümde WordPress'in revizyon kimliğini bir yere not edin ve siparişe revizyon numarasını yazın. Böylece hem depolama maliyeti düşük kalır hem de istendiğinde o günkü metni revizyon geçmişinden geri getirebilirsiniz.
Hangi yöntemi seçerseniz seçin, yukarıda değindiğimiz üç yıllık saklama yükümlülüğünü göz önünde bulundurun. Bu, veritabanı yedeklerinizin de en az o kadar geriye gitmesi gerektiği anlamına gelir; yedekleme planınızı buna göre kurun.
Metinleri Müşteriye E-posta ile İletmek#
Onayı kaydetmek yarısı; diğer yarısı bilgilendirmenin tüketiciye kalıcı biçimde ulaştığını gösterebilmektir. Sipariş onay e-postasına sözleşme bağlantılarını ve onay bilgisini eklemek hem müşteriye güven verir hem de sizin lehinize bir kayıt oluşturur.
add_action( 'woocommerce_email_after_order_table', 'clou_epostaya_sozlesme_ekle', 20, 4 );
function clou_epostaya_sozlesme_ekle( $order, $sent_to_admin, $plain_text, $email ) {
if ( $sent_to_admin || 'customer_processing_order' !== $email->id ) {
return;
}
$zaman = $order->get_meta( '_clou_sozlesme_onay_zamani' );
if ( ! $zaman ) {
return;
}
echo '<h2>Sözleşme Bilgileri</h2>';
echo '<p>Siparişiniz sırasında aşağıdaki metinleri onayladınız (' . esc_html( $zaman ) . '):</p>';
echo '<ul>';
echo '<li><a href="' . esc_url( home_url( '/on-bilgilendirme-formu/' ) ) . '">Ön Bilgilendirme Formu</a></li>';
echo '<li><a href="' . esc_url( home_url( '/mesafeli-satis-sozlesmesi/' ) ) . '">Mesafeli Satış Sözleşmesi</a></li>';
echo '</ul>';
}
E-posta kimliğini kontrol etmeyi atlamayın; aksi takdirde aynı blok iade, iptal ve yönetici bildirimlerine de eklenir. customer_processing_order yerine mağazanızın akışına göre customer_completed_order veya customer_on_hold_order uygun olabilir. Havale/EFT ile çalışıyorsanız beklemedeki sipariş e-postası da doğru bir hedeftir.
Bu e-postaların gerçekten teslim edildiğinden emin olun. Paylaşımlı sunucudan doğrudan gönderilen bildirimler sıkça istenmeyen klasörüne düşer; müşteriye ulaşmamış bir bilgilendirme, hukuken de zayıf bir kayıttır.
Sık Yapılan Hatalar#
Belirti: Onay kutusu ödeme sayfasında hiç görünmüyor.
Sebep: Ödeme sayfası blok tabanlı ama klasik kancalar kullanılmış.
Çözüm: Sayfayı düzenleyip Ödeme bloğu mu yoksa [woocommerce_checkout] kısa kodu mu olduğunu kontrol edin; blok ise ek alanlar API'sine geçin.
Belirti: Onay kutusu görünüyor ama işaretlenmeden sipariş geçiyor.
Sebep: Yalnızca görsel alan eklenmiş, woocommerce_checkout_process doğrulaması yazılmamış.
Çözüm: Sunucu tarafı doğrulamayı ekleyin. Tarayıcı doğrulaması hiçbir zaman tek başına yeterli değildir.
Belirti: Sipariş notunda onay kaydı yok ama meta veri var.
Sebep: Not, siparişin kimliği oluşmadan önceki kancada eklenmeye çalışılmış.
Çözüm: Notu woocommerce_checkout_order_processed içinde ekleyin.
Belirti: Ödeme altyapısına yönlendirilen siparişlerde onay bilgisi eksik kalıyor. Sebep: Bazı ödeme entegrasyonları siparişi farklı bir akışla oluşturur ve klasik ödeme alanlarını taşımaz. Çözüm: Entegrasyonunuzla birlikte test siparişi verip meta verinin yazıldığını doğrulayın. Kart ödemesi tarafında test için WooCommerce iyzico entegrasyonu yazımızdaki sanal POS test akışından yararlanabilirsiniz.
Belirti: Fiyat ve kargo bedeli sözleşme metninde yazandan farklı görünüyor. Sebep: Metinde sabit tutar yazılmış, ama vergi veya kargo kuralları değişmiş. Çözüm: Sözleşme metninde sabit rakam yerine "sipariş özetinde belirtilen tutar" ifadesini kullanın; KDV ve kargo yapılandırmasını WooCommerce KDV ve vergi ayarları ile kargo ayarları yazılarımıza göre netleştirin.
Sıkça Sorulan Sorular#
Ön bilgilendirme formu ve mesafeli satış sözleşmesi için tek onay kutusu yeterli mi?#
Teknik olarak sipariş geçer, ancak ispat açısından zayıf bir kurulumdur. Bu iki metnin işlevleri farklıdır: biri sipariş kurulmadan önce bilgilendirme, diğeri sözleşmenin kendisi. Ayrı kutularla onaylatmak, hangi metnin ne zaman kabul edildiğini kayıt altına almanızı sağlar ve olası bir uyuşmazlıkta elinizi belirgin biçimde güçlendirir. Uygulama maliyeti de yalnızca birkaç satır koddur.
Onay kutusunu işaretlemeden sipariş verilebiliyor, neden?#
Büyük olasılıkla yalnızca görsel alan eklenmiş, sunucu tarafında doğrulama yazılmamıştır. Tarayıcıdaki zorunluluk özniteliği geliştirici araçlarıyla kolayca kaldırılabilir. woocommerce_checkout_process kancasında boş değeri yakalayıp wc_add_notice ile hata döndürdüğünüzde sipariş sunucu tarafında engellenir; asıl koruma budur.
Müşterinin onay verdiğini nasıl ispatlarım?#
Üç bilgiyi birlikte saklamanız gerekir: onayın verildiği tarih ve saat, siparişin kimliği ve o anda yürürlükte olan metnin sürümü. İlk ikisi sipariş notuna ve sipariş meta verisine yazılabilir. Üçüncüsü çoğu mağazada atlanır ve en kritik olanıdır; metnin özetini, revizyon numarasını veya PDF kopyasını siparişe bağlamadan "hangi metni onayladı" sorusuna cevap veremezsiniz.
Sözleşme metnini güncellersem eski siparişler etkilenir mi?#
Eski siparişler için geçerli olan, siparişin verildiği andaki metindir; sonradan yaptığınız değişiklik geriye yürümez. Sorun hukuki değil, pratik: eğer o günkü metni saklamadıysanız artık gösteremezsiniz. Bu yüzden metni her güncellediğinizde önceki sürümü arşivleyin ve siparişlere sürüm bilgisi yazan bir mekanizma kurun.
Bu metinleri ne kadar süre saklamam gerekiyor?#
Mesafeli Sözleşmeler Yönetmeliği, bilgilendirme ve cayma hakkına ilişkin her işleme dair bilgi ve belgenin üç yıl saklanmasını öngörür. Pratikte bu, sipariş kayıtlarınızın, onay verilerinizin ve metin sürümlerinizin en az üç yıl erişilebilir kalması demektir. Yedekleme planınızı da buna göre kurgulayın; üç yıl önceki bir siparişi geri getiremiyorsanız kayıt tutmuş sayılmazsınız.
Hazır bir eklenti kullanmak yerine kod yazmak şart mı?#
Şart değil. Sözleşme onayı ekleyen birçok eklenti var ve küçük mağazalar için makul bir başlangıçtır. Ancak eklenti seçerken üç şeyi kontrol edin: sunucu tarafında doğrulama yapıyor mu, onayı siparişe kalıcı olarak yazıyor mu ve blok tabanlı ödeme sayfasını destekliyor mu? Yalnızca ekrana kutu basan bir eklenti, ihtiyacınız olan kaydı üretmez.
Onay kaydında IP adresi tutmak KVKK açısından sorun yaratır mı?#
IP adresi kişisel veri sayılır, dolayısıyla işlenmesi bir hukuki sebebe dayanmalı ve aydınlatma metninizde yer almalıdır. Sözleşme onayının ispatı için tutulan IP kaydı genellikle sözleşmenin kurulması ve hukuki yükümlülüğün yerine getirilmesi kapsamında değerlendirilir. Yine de saklama süresini sınırlayın, veriyi yalnızca gerektiği kadar tutun ve aydınlatma metninizde bu işlemeye açıkça yer verin.