WooCommerce → Minimum Sepet Popup menüsü, sepet tutarı belirlediğiniz minimum limitin altındayken müşterinin ödeme ekranına ilerlemesini engellemek için kullanılır. Bu kural, özellikle kargo, paketleme, komisyon veya operasyon maliyetlerinin düşük sepetlerde zarar oluşturduğu mağazalarda standart bir uygulamadır. Eski usul perakendede “asgari alışveriş” kuralı neyse, online tarafta bunun karşılığı budur: düzen sağlar, yanlış anlaşılmayı azaltır, sipariş kalitesini yükseltir.
Bu sayfadan üç temel ayarı yönetirsiniz. Minimum Sepet Tutarı alanına örneğin 250 yazdığınızda, sepet toplamı bu değerin altındaysa sistem ödeme sayfasına geçişi otomatik olarak durdurur. Müşteri ödeme adımına gitmeye çalıştığında ekranda uyarı penceresi çıkar ve “Alışverişe Devam Et” butonuyla mağazaya geri yönlendirilir. Böylece kural net biçimde görünür, kullanıcı boş yere form doldurmaz, siz de sipariş akışını kontrol altında tutarsınız.
Popup Mesajı bölümünde müşteriye gösterilecek metni serbestçe düzenleyebilirsiniz. Mesaj içinde {min} ve {currency} yer tutucularını kullanarak minimum tutarı ve para birimi sembolünü otomatik gösterebilirsiniz. Buton Yazısı alanı ise uyarı penceresindeki buton metnini değiştirmenizi sağlar. Tüm değişiklikler Kaydet ile anında aktif olur ve hem klasik sepet/ödeme sayfalarında hem de blok tabanlı WooCommerce sayfalarında geçerlidir.
if (!defined('ABSPATH')) exit;
final class DW_Min_Sepet_Popup_Admin {
const OPT_KEY = 'dw_min_sepet_popup_opts';
const QUERY_FLAG = 'dw_min_cart';
public function __construct() {
add_action('admin_menu', [$this, 'admin_menu']);
add_action('admin_init', [$this, 'admin_init']);
add_action('template_redirect', [$this, 'redirect_checkout_if_below_min'], 20);
add_action('wp_loaded', [$this, 'override_classic_cart_button_if_needed'], 20);
add_action('wp_enqueue_scripts', [$this, 'enqueue_inline_assets'], 99);
add_action('woocommerce_checkout_process', [$this, 'block_checkout_submit'], 10);
}
/* =========================
* Helpers / Options
* ========================= */
private function wc_ready(): bool {
return class_exists('WooCommerce') && function_exists('WC') && WC()->cart;
}
private function defaults(): array {
return [
'minimum_amount' => 250,
'message_template' => 'Ödeme Ekranına Geçebilmeniz İçin Minimum Sepet Tutarınız {min}{currency} Olmalıdır.',
'button_text' => 'Alışverişe Devam Et',
];
}
private function get_opts(): array {
$opts = get_option(self::OPT_KEY, []);
if (!is_array($opts)) $opts = [];
return array_merge($this->defaults(), $opts);
}
private function currency_symbol_decoded(): string {
$sym = function_exists('get_woocommerce_currency_symbol') ? (string) get_woocommerce_currency_symbol() : '₺';
// WooCommerce bazı sembolleri ₺ gibi entity döndürebiliyor -> decode ediyoruz
$sym = html_entity_decode($sym, ENT_QUOTES | ENT_HTML5, 'UTF-8');
return $sym ?: '₺';
}
/**
* Min tutarı hangi toplamdan hesaplayalım?
* Varsayılan: ürünler toplamı (genelde indirim sonrası), kargo & vergi hariç.
*/
private function cart_amount(): float {
if (!$this->wc_ready()) return 0.0;
$amount = (float) WC()->cart->get_cart_contents_total();
return max(0.0, $amount);
}
private function minimum_amount(): float {
$opts = $this->get_opts();
$min = isset($opts['minimum_amount']) ? (float) $opts['minimum_amount'] : 250.0;
if ($min < 0) $min = 0;
return $min;
}
private function is_below_min(): bool {
return $this->cart_amount() + 0.00001 < $this->minimum_amount();
}
private function cart_url(): string {
return function_exists('wc_get_cart_url') ? (string) wc_get_cart_url() : home_url('/cart/');
}
private function checkout_url(): string {
return function_exists('wc_get_checkout_url') ? (string) wc_get_checkout_url() : home_url('/checkout/');
}
private function continue_url(): string {
if (function_exists('wc_get_page_permalink')) {
$shop = wc_get_page_permalink('shop');
if (!empty($shop)) return (string) $shop;
}
return home_url('/');
}
private function is_checkout_endpoint_ok(): bool {
if (!function_exists('is_wc_endpoint_url')) return false;
return is_wc_endpoint_url('order-received') || is_wc_endpoint_url('order-pay');
}
private function is_cart_like_page(): bool {
if (function_exists('is_cart') && is_cart()) return true;
if (function_exists('wc_get_page_id')) {
$cart_id = (int) wc_get_page_id('cart');
if ($cart_id > 0 && is_page($cart_id)) return true;
}
if (is_singular('page') && function_exists('has_block')) {
global $post;
if ($post && isset($post->post_content)) {
if (has_block('woocommerce/cart', $post->post_content)) return true;
}
}
return false;
}
private function is_checkout_like_page(): bool {
if (function_exists('is_checkout') && is_checkout()) return true;
if (function_exists('wc_get_page_id')) {
$chk_id = (int) wc_get_page_id('checkout');
if ($chk_id > 0 && is_page($chk_id)) return true;
}
if (is_singular('page') && function_exists('has_block')) {
global $post;
if ($post && isset($post->post_content)) {
if (has_block('woocommerce/checkout', $post->post_content)) return true;
}
}
return false;
}
private function build_message(): string {
$opts = $this->get_opts();
$tpl = (string) ($opts['message_template'] ?? $this->defaults()['message_template']);
// Kullanıcı mesajı içine entity yazdıysa onu da decode edelim
$tpl = html_entity_decode($tpl, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$repl = [
'{min}' => $this->format_min_amount(),
'{currency}' => $this->currency_symbol_decoded(),
];
return strtr($tpl, $repl);
}
private function format_min_amount(): string {
$min = $this->minimum_amount();
// 250.00 gibi olmasın diye gereksiz sıfırları kırp
if (abs($min - round($min)) < 0.00001) return (string) (int) round($min);
return rtrim(rtrim(number_format($min, 2, '.', ''), '0'), '.');
}
/* =========================
* Front: Block/Classic Guard
* ========================= */
public function redirect_checkout_if_below_min() {
if (!$this->wc_ready()) return;
if (wp_doing_ajax()) return;
if (!$this->is_checkout_like_page()) return;
if ($this->is_checkout_endpoint_ok()) return;
if ($this->is_below_min()) {
if (function_exists('wc_add_notice')) {
wc_add_notice($this->build_message(), 'error');
}
$url = add_query_arg(self::QUERY_FLAG, '1', $this->cart_url());
wp_safe_redirect($url);
exit;
}
}
public function block_checkout_submit() {
if (!$this->wc_ready()) return;
if (!$this->is_below_min()) return;
if (function_exists('wc_add_notice')) {
wc_add_notice($this->build_message(), 'error');
}
}
public function override_classic_cart_button_if_needed() {
if (!$this->wc_ready()) return;
if (!$this->is_cart_like_page()) return;
if (function_exists('woocommerce_button_proceed_to_checkout')) {
remove_action('woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20);
add_action('woocommerce_proceed_to_checkout', function () {
if ($this->is_below_min()) {
echo '<button type="button" class="checkout-button button alt wc-forward dw-mincart-trigger">'
. esc_html__('Ödemeye Geç', 'dw-min-sepet')
. '</button>';
} else {
woocommerce_button_proceed_to_checkout();
}
}, 20);
}
}
public function enqueue_inline_assets() {
if (!$this->wc_ready()) return;
if (!$this->is_cart_like_page() && !$this->is_checkout_like_page()) return;
if (!$this->is_below_min()) return;
$opts = $this->get_opts();
$data = [
'message' => $this->build_message(),
'autoOpen' => (isset($_GET[self::QUERY_FLAG]) && $_GET[self::QUERY_FLAG] === '1'),
'continueUrl' => $this->continue_url(),
'checkoutUrl' => $this->checkout_url(),
'buttonText' => (string) ($opts['button_text'] ?? $this->defaults()['button_text']),
];
wp_register_style('dw-mincart-inline', false, [], '1.1.0');
wp_enqueue_style('dw-mincart-inline');
// Daha küçük tasarım (sende çok büyüktü)
$css = <<<CSS
#dw-mincart-overlay{
position:fixed; inset:0; background:rgba(0,0,0,.35);
display:none; align-items:center; justify-content:center;
z-index:999999; padding:16px;
}
#dw-mincart-overlay.is-open{ display:flex; }
#dw-mincart-box{
width:min(760px, 100%);
background:#fff;
border-radius:16px;
box-shadow:0 10px 40px rgba(0,0,0,.25);
padding:30px 20px 22px;
position:relative;
}
#dw-mincart-close{
position:absolute; top:10px; right:12px;
width:36px; height:36px;
border:0; background:transparent;
font-size:26px; line-height:36px;
cursor:pointer; opacity:.65;
}
#dw-mincart-close:hover{ opacity:1; }
#dw-mincart-text{
text-align:center;
font-size:28px; line-height:1.2;
font-weight:800;
color:#111;
padding:0 8px;
}
@media (max-width:768px){
#dw-mincart-text{ font-size:20px; }
#dw-mincart-box{ padding:22px 16px 18px; }
}
#dw-mincart-actions{ display:flex; justify-content:center; margin-top:16px; }
#dw-mincart-btn{
display:inline-flex; align-items:center; justify-content:center; text-decoration:none;
height:50px;
padding:0 28px;
border-radius:14px;
background:#7a4a3b;
color:#fff;
font-size:20px;
font-weight:700;
}
#dw-mincart-btn:hover{ filter:brightness(.95); }
CSS;
wp_add_inline_style('dw-mincart-inline', $css);
wp_register_script('dw-mincart-inline', false, [], '1.1.0', true);
wp_enqueue_script('dw-mincart-inline');
$json = wp_json_encode($data);
$js = <<<JS
(function(){
var CFG = $json;
function qs(sel, root){ return (root||document).querySelector(sel); }
function closestEl(el, sel){
while(el && el.nodeType === 1){
if(el.matches(sel)) return el;
el = el.parentElement;
}
return null;
}
function ensureModal(){
if(qs('#dw-mincart-overlay')) return;
var overlay = document.createElement('div');
overlay.id = 'dw-mincart-overlay';
overlay.setAttribute('aria-hidden','true');
overlay.innerHTML =
'<div id="dw-mincart-box" role="dialog" aria-modal="true" aria-label="Minimum sepet tutarı uyarısı">' +
'<button id="dw-mincart-close" type="button" aria-label="Kapat">×</button>' +
'<div id="dw-mincart-text"></div>' +
'<div id="dw-mincart-actions">' +
'<a id="dw-mincart-btn" href="#"></a>' +
'</div>' +
'</div>';
document.body.appendChild(overlay);
overlay.addEventListener('click', function(e){
if(e.target === overlay) closeModal();
});
qs('#dw-mincart-close', overlay).addEventListener('click', closeModal);
document.addEventListener('keydown', function(e){
if(e.key === 'Escape') closeModal();
});
}
function openModal(){
ensureModal();
var overlay = qs('#dw-mincart-overlay');
qs('#dw-mincart-text', overlay).textContent = CFG.message || 'Minimum sepet tutarı şartı var.';
var btn = qs('#dw-mincart-btn', overlay);
btn.textContent = CFG.buttonText || 'Alışverişe Devam Et';
btn.href = CFG.continueUrl || '/';
overlay.classList.add('is-open');
overlay.setAttribute('aria-hidden','false');
}
function closeModal(){
var overlay = qs('#dw-mincart-overlay');
if(!overlay) return;
overlay.classList.remove('is-open');
overlay.setAttribute('aria-hidden','true');
}
// Checkout'a giden tıklamaları yakala (blok + klasik)
function intercept(e){
var clickable = closestEl(e.target, 'a, button');
if(!clickable) return;
// Klasik buton
if(clickable.classList && (clickable.classList.contains('dw-mincart-trigger') || clickable.classList.contains('checkout-button'))){
e.preventDefault(); e.stopPropagation(); if(e.stopImmediatePropagation) e.stopImmediatePropagation();
openModal(); return;
}
// Link ile checkout
if(clickable.tagName === 'A'){
var href = clickable.getAttribute('href') || '';
if(!href) return;
if((CFG.checkoutUrl && href.indexOf(CFG.checkoutUrl) === 0) || href.indexOf('checkout') !== -1){
e.preventDefault(); e.stopPropagation(); if(e.stopImmediatePropagation) e.stopImmediatePropagation();
openModal(); return;
}
}
// Blok cart submit sınıfları
var cls = (clickable.className || '').toString();
if(cls.indexOf('wc-block-cart__submit') !== -1 || cls.indexOf('proceed-to-checkout') !== -1){
e.preventDefault(); e.stopPropagation(); if(e.stopImmediatePropagation) e.stopImmediatePropagation();
openModal(); return;
}
}
document.addEventListener('click', intercept, true);
if(CFG.autoOpen){
document.addEventListener('DOMContentLoaded', function(){ openModal(); });
}
})();
JS;
wp_add_inline_script('dw-mincart-inline', $js, 'after');
}
/* =========================
* Admin Settings
* ========================= */
public function admin_menu() {
if (!current_user_can('manage_woocommerce')) return;
add_submenu_page(
'woocommerce',
'Minimum Sepet Popup',
'Minimum Sepet Popup',
'manage_woocommerce',
'dw-min-sepet-popup',
[$this, 'settings_page']
);
}
public function admin_init() {
register_setting('dw_min_sepet_popup_group', self::OPT_KEY, [$this, 'sanitize_opts']);
add_settings_section(
'dw_min_sepet_popup_section',
'Ayarlar',
function(){
echo '<p>Mesaj içinde şu yer tutucuları kullanabilirsin: <code>{min}</code> ve <code>{currency}</code></p>';
},
'dw-min-sepet-popup'
);
add_settings_field(
'minimum_amount',
'Minimum Sepet Tutarı',
[$this, 'field_minimum_amount'],
'dw-min-sepet-popup',
'dw_min_sepet_popup_section'
);
add_settings_field(
'message_template',
'Popup Mesajı',
[$this, 'field_message_template'],
'dw-min-sepet-popup',
'dw_min_sepet_popup_section'
);
add_settings_field(
'button_text',
'Buton Yazısı',
[$this, 'field_button_text'],
'dw-min-sepet-popup',
'dw_min_sepet_popup_section'
);
}
public function sanitize_opts($input) {
$out = $this->get_opts();
if (is_array($input)) {
if (isset($input['minimum_amount'])) {
$min = (float) str_replace(',', '.', (string) $input['minimum_amount']);
if ($min < 0) $min = 0;
$out['minimum_amount'] = $min;
}
if (isset($input['message_template'])) {
$msg = sanitize_textarea_field((string) $input['message_template']);
$out['message_template'] = $msg ?: $this->defaults()['message_template'];
}
if (isset($input['button_text'])) {
$btn = sanitize_text_field((string) $input['button_text']);
$out['button_text'] = $btn ?: $this->defaults()['button_text'];
}
}
return $out;
}
public function field_minimum_amount() {
$opts = $this->get_opts();
$val = esc_attr((string) $opts['minimum_amount']);
echo '<input type="number" step="0.01" min="0" name="'.esc_attr(self::OPT_KEY).'[minimum_amount]" value="'.$val.'" style="width:160px;">';
echo '<p class="description">Örn: 250</p>';
}
public function field_message_template() {
$opts = $this->get_opts();
$val = esc_textarea((string) $opts['message_template']);
echo '<textarea name="'.esc_attr(self::OPT_KEY).'[message_template]" rows="3" style="width:520px; max-width:100%;">'.$val.'</textarea>';
echo '<p class="description">Örn: Ödeme Ekranına Geçebilmeniz İçin Minimum Sepet Tutarınız {min}{currency} Olmalıdır.</p>';
}
public function field_button_text() {
$opts = $this->get_opts();
$val = esc_attr((string) $opts['button_text']);
echo '<input type="text" name="'.esc_attr(self::OPT_KEY).'[button_text]" value="'.$val.'" style="width:300px; max-width:100%;">';
}
public function settings_page() {
if (!current_user_can('manage_woocommerce')) return;
echo '<div class="wrap"><h1>Minimum Sepet Popup</h1>';
echo '<form method="post" action="options.php">';
settings_fields('dw_min_sepet_popup_group');
do_settings_sections('dw-min-sepet-popup');
submit_button('Kaydet');
echo '</form></div>';
}
}
add_action('plugins_loaded', function(){
if (!class_exists('WooCommerce')) return;
new DW_Min_Sepet_Popup_Admin();
});