Banner

Cart Dynamic Discount

Adds a progressive discount based on the shopping cart.

Display estimated delivery date
PHP
/**
 * Snippet Name:     Cart Dynamic Discount
 * Snippet Author:   coding-bunny.com
 * Description:      Adds a progressive discount based on the shopping cart.
 */

// === ADD DISCOUNT HERE ===
function cbpds_get_discount_tiers() {
    return [
        50  => 5,   // Example: €50 = 5% discount
        150 => 10,
        250 => 15,
        500 => 25
    ];
}

add_action('woocommerce_cart_calculate_fees', 'cbpds_apply_cart_discount');
function cbpds_apply_cart_discount() {
    if (is_admin() && !defined('DOING_AJAX')) return;
    if (!WC()->cart) return;
    
    $cart_total = WC()->cart->get_subtotal();
    $discount_percentage = cbpds_get_discount_percentage($cart_total);
    
    if ($discount_percentage > 0) {
        $discount_amount = ($cart_total * $discount_percentage) / 100;
        $discount_label = sprintf('Discount %d%% (-€%.2f)', $discount_percentage, $discount_amount);
        
        WC()->cart->add_fee($discount_label, -$discount_amount);
    }
}

function cbpds_get_discount_percentage($total) {
    $discount = 0;
    foreach (cbpds_get_discount_tiers() as $threshold => $percentage) {
        if ($total >= $threshold) {
            $discount = $percentage;
        }
    }
    return $discount;
}

add_action('wp_ajax_cbpds_update_progress', 'cbpds_ajax_update_progress');
add_action('wp_ajax_nopriv_cbpds_update_progress', 'cbpds_ajax_update_progress');

function cbpds_ajax_update_progress() {
    if (!wp_verify_nonce($_POST['nonce'], 'cbpds_nonce')) {
        wp_die('Security check failed');
    }
    
    $cart_total = WC()->cart ? WC()->cart->get_subtotal() : 0;
    $progress_data = cbpds_calculate_progress($cart_total);
    $tiers = cbpds_get_discount_tiers();
    
    ob_start();
    ?>
    <div class="cbpds-minimal-steps">
        <?php foreach ($tiers as $tier => $discount): 
            $is_achieved = $cart_total >= $tier;
            $is_current = !$is_achieved && $progress_data['next_tier'] == $tier;
        ?>
            <div class="cbpds-minimal-step <?php echo $is_achieved ? 'achieved' : ($is_current ? 'current' : ''); ?>">
                <div class="cbpds-spend-row">
                    <span class="cbpds-label">Spend</span>
                    <span class="cbpds-amount"><?php echo $tier; ?></span>
                </div>
                <div class="cbpds-discount-row">
                    <span class="cbpds-label">Discount</span>
                    <span class="cbpds-percent"><?php echo $discount; ?>%</span>
                </div>
                <?php if ($is_achieved): ?>
                    <div class="cbpds-minimal-check"></div>
                <?php endif; ?>
            </div>
        <?php endforeach; ?>
    </div>
    
    <?php if ($progress_data['next_tier']): ?>
        <div class="cbpds-minimal-progress">
            <div class="cbpds-minimal-bar">
                <div class="cbpds-minimal-fill" style="width: <?php echo $progress_data['progress_percentage']; ?>%"></div>
            </div>
            <div class="cbpds-minimal-text">
                <?php if ($progress_data['remaining_amount'] > 0): ?>
<?php echo number_format($progress_data['remaining_amount'], 2); ?> remaining for <?php echo $tiers[$progress_data['next_tier']]; ?>% discount
                <?php endif; ?>
            </div>
        </div>
    <?php else: ?>
        <div class="cbpds-minimal-complete">
            Maximum discount reached
        </div>
    <?php endif; ?>
    <?php
    
    $html = ob_get_clean();
    
    wp_send_json_success([
        'html' => $html,
        'cart_total' => $cart_total,
        'current_discount' => $progress_data['current_discount']
    ]);
}

// === ADD HERE WHERE TO SHOW IT ===
add_action('woocommerce_after_add_to_cart_button', 'cbpds_show_minimal_progress_bar', 25);
add_action('woocommerce_before_cart_table', 'cbpds_show_minimal_progress_bar');
add_action('woocommerce_review_order_before_payment', 'cbpds_show_minimal_progress_bar');

function cbpds_show_minimal_progress_bar() {
    $cart_total = WC()->cart ? WC()->cart->get_subtotal() : 0;
    $progress_data = cbpds_calculate_progress($cart_total);
    $tiers = cbpds_get_discount_tiers();
    
    ?>
    <div class="cbpds-minimal-container" id="cbpds-progress-container">
        
        <div class="cbpds-minimal-steps">
            <?php foreach ($tiers as $tier => $discount): 
                $is_achieved = $cart_total >= $tier;
                $is_current = !$is_achieved && $progress_data['next_tier'] == $tier;
            ?>
                <div class="cbpds-minimal-step <?php echo $is_achieved ? 'achieved' : ($is_current ? 'current' : ''); ?>">
                    <div class="cbpds-spend-row">
                        <span class="cbpds-label">Spend</span>
                        <span class="cbpds-amount"><?php echo $tier; ?></span>
                    </div>
                    <div class="cbpds-discount-row">
                        <span class="cbpds-label">Discount</span>
                        <span class="cbpds-percent"><?php echo $discount; ?>%</span>
                    </div>
                    <?php if ($is_achieved): ?>
                        <div class="cbpds-minimal-check"></div>
                    <?php endif; ?>
                </div>
            <?php endforeach; ?>
        </div>
        
        <?php if ($progress_data['next_tier']): ?>
            <div class="cbpds-minimal-progress">
                <div class="cbpds-minimal-bar">
                    <div class="cbpds-minimal-fill" style="width: <?php echo $progress_data['progress_percentage']; ?>%"></div>
                </div>
                <div class="cbpds-minimal-text">
                    <?php if ($progress_data['remaining_amount'] > 0): ?>
<?php echo number_format($progress_data['remaining_amount'], 2); ?> remaining for <?php echo $tiers[$progress_data['next_tier']]; ?>% discount
                    <?php endif; ?>
                </div>
            </div>
        <?php else: ?>
            <div class="cbpds-minimal-complete">
                Maximum discount reached
            </div>
        <?php endif; ?>
        
    </div>
    
    <style>
    .cbpds-minimal-container {
        background: #f8f9fa;
        border: 1px solid #e9ecef;
        border-radius: 6px;
        padding: 16px;
        margin: 16px 0;
        font-size: 14px;
        color: #495057;
    }
    
    .cbpds-minimal-steps {
        display: flex;
        gap: 8px;
        margin-bottom: 12px;
        flex-wrap: wrap;
    }
    
    .cbpds-minimal-step {
        flex: 1;
        min-width: 100px;
        text-align: center;
        padding: 12px 8px;
        border-radius: 4px;
        position: relative;
        transition: all 0.2s ease;
        display: flex;
        flex-direction: column;
        gap: 6px;
    }
    
    .cbpds-minimal-step:not(.achieved):not(.current) {
        background: #f8f9fa;
        border: 1px solid #dee2e6;
        color: #6c757d;
    }
    
    .cbpds-minimal-step.current {
        background: #fff3cd;
        border: 1px solid #ffeaa7;
        color: #856404;
    }
    
    .cbpds-minimal-step.achieved {
        background: #d4edda;
        border: 1px solid #c3e6cb;
        color: #155724;
    }
    
    .cbpds-spend-row,
    .cbpds-discount-row {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
    }
    
    .cbpds-label {
        font-size: 10px;
        font-weight: 500;
        text-transform: uppercase;
        letter-spacing: 0.5px;
        opacity: 0.7;
        white-space: nowrap;
    }
    
    .cbpds-amount,
    .cbpds-percent {
        font-size: 12px;
        font-weight: 700;
    }
       
    .cbpds-minimal-check {
        position: absolute;
        top: -2px;
        right: -2px;
        background: #28a745;
        color: white;
        width: 16px;
        height: 16px;
        border-radius: 50%;
        font-size: 10px;
        display: flex;
        align-items: center;
        justify-content: center;
        line-height: 1;
    }
    
    .cbpds-minimal-progress {
        margin-top: 12px;
    }
    
    .cbpds-minimal-bar {
        background: #e9ecef;
        border-radius: 3px;
        height: 6px;
        overflow: hidden;
        margin-bottom: 6px;
    }
    
    .cbpds-minimal-fill {
        background: #29a745;
        height: 100%;
        border-radius: 3px;
        transition: width 0.3s ease;
    }
    
    .cbpds-minimal-text {
        text-align: center;
        font-size: 12px;
        color: #6c757d;
        font-weight: 500;
    }
    
    .cbpds-minimal-complete {
        background: #d4edda;
        color: #155724;
        padding: 10px 12px;
        border-radius: 4px;
        text-align: center;
        font-weight: 500;
        border: 1px solid #c3e6cb;
        font-size: 13px;
    }
    
    @media (max-width: 768px) {
        .cbpds-minimal-container {
            padding: 12px;
            font-size: 13px;
        }
        
        .cbpds-minimal-steps {
            flex-direction: column;
            gap: 6px;
        }
        
        .cbpds-minimal-step {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            align-items: center;
            padding: 12px;
            text-align: left;
            min-width: auto;
            gap: 8px;
        }
        
        .cbpds-spend-row,
        .cbpds-discount-row {
            justify-content: flex-start;
        }
        
        .cbpds-spend-row {
            order: 1;
        }
        
        .cbpds-discount-row {
            order: 2;
        }
        
        .cbpds-minimal-check {
            position: static;
            order: 3;
            margin-left: auto;
        }
    }
    
    @media (max-width: 480px) {
        .cbpds-minimal-container {
            margin: 12px 0;
            padding: 10px;
        }
        
        .cbpds-amount {
            font-size: 12px;
        }
        
        .cbpds-percent {
            font-size: 14px;
        }
        
        .cbpds-label {
            font-size: 9px;
        }
    }
    </style>
    
    <script>
    jQuery(document).ready(function($) {
        var cbpds_nonce = '<?php echo wp_create_nonce('cbpds_nonce'); ?>';
        var cbpds_ajax_url = '<?php echo admin_url('admin-ajax.php'); ?>';
        var cbpds_updating = false;
        
        function cbpds_update_progress() {
            if (cbpds_updating) return;
            cbpds_updating = true;
            
            var $container = $('#cbpds-progress-container');
            
            $.post(cbpds_ajax_url, {
                action: 'cbpds_update_progress',
                nonce: cbpds_nonce
            })
            .done(function(response) {
                if (response.success) {
                    $container.html(response.data.html);
                    cbpds_bind_hover_events();
                }
            })
            .fail(function() {
                console.log('CBPDS: Error updating progress bar');
            })
            .always(function() {
                cbpds_updating = false;
            });
        }
        
        function cbpds_bind_hover_events() {
            $('.cbpds-minimal-step').off('mouseenter mouseleave').hover(
                function() {
                    if (!$(this).hasClass('achieved')) {
                        $(this).css('transform', 'translateY(-1px)');
                    }
                },
                function() {
                    $(this).css('transform', 'translateY(0)');
                }
            );
        }
        
        cbpds_bind_hover_events();
        
        $(document.body).on('added_to_cart removed_from_cart updated_cart_totals updated_checkout', function() {
            setTimeout(cbpds_update_progress, 100);
        });
        
        $(document.body).on('wc_fragments_refreshed wc_fragments_loaded', function() {
            setTimeout(cbpds_update_progress, 100);
        });
        
        $(document).on('change', '.qty', function() {
            setTimeout(cbpds_update_progress, 500);
        });
        
        $('form.cart').on('submit', function() {
            setTimeout(cbpds_update_progress, 1000);
        });
        
        if ($('body').hasClass('woocommerce-cart') || $('body').hasClass('woocommerce-checkout')) {
            setInterval(cbpds_update_progress, 3000);
        }
    });
    </script>
    <?php
}

function cbpds_calculate_progress($total) {
    $tiers = cbpds_get_discount_tiers();
    $tier_keys = array_keys($tiers);
    $current_tier = 0;
    $current_discount = 0;
    $next_tier = $tier_keys[0];
    $progress_percentage = 0;
    
    foreach ($tier_keys as $tier) {
        if ($total >= $tier) {
            $current_tier = $tier;
            $current_discount = $tiers[$tier];
        }
    }
    
    foreach ($tier_keys as $tier) {
        if ($total < $tier) {
            $next_tier = $tier;
            break;
        }
    }
    
    if ($total >= max($tier_keys)) {
        $progress_percentage = 100;
        $next_tier = null;
    } else {
        $previous_tier = 0;
        foreach ($tier_keys as $tier) {
            if ($tier < $next_tier) {
                $previous_tier = $tier;
            }
        }
        
        if ($next_tier > $previous_tier) {
            $progress_percentage = (($total - $previous_tier) / ($next_tier - $previous_tier)) * 100;
        }
    }
    
    return [
        'current_tier' => $current_tier,
        'current_discount' => $current_discount,
        'next_tier' => $next_tier,
        'progress_percentage' => min(100, max(0, $progress_percentage)),
        'remaining_amount' => $next_tier ? max(0, $next_tier - $total) : 0
    ];
}

?>

How To Implement This Solution?

Leave a Reply

My Agile Privacy
This site uses technical and profiling cookies. You can accept, decline or customize cookies by pressing the desired buttons. By closing this policy you will continue without accepting.

Need help?

Choose one of the following options:

Powered by CodingBunny