/* =========================================================
FREE SHIPPING PROGRESS BAR – AJAX SAFE (KADENCE)
========================================================= */
/* ---------- GET FREE SHIPPING LIMIT FROM WC ---------- */
function kas_get_free_shipping_limit() {
if ( ! WC()->cart ) return 0;
$packages = WC()->cart->get_shipping_packages();
foreach ( $packages as $package ) {
$zone = WC_Shipping_Zones::get_zone_matching_package( $package );
$methods = $zone->get_shipping_methods( true );
foreach ( $methods as $method ) {
if (
$method->id === 'free_shipping' &&
$method->enabled === 'yes' &&
isset( $method->min_amount ) &&
$method->min_amount > 0
) {
return (float) $method->min_amount;
}
}
}
return 0;
}
/* ---------- CORE RENDER FUNCTION ---------- */
function kas_render_free_shipping_bar() {
if ( ! WC()->cart ) return;
$limit = kas_get_free_shipping_limit();
if ( $limit <= 0 ) return;
$subtotal = WC()->cart->get_subtotal();
if ( $subtotal >= $limit ) {
?>
<div class="kas-free-shipping-wrap">
<div class="kas-free-shipping-text">You unlocked Free Shipping</div>
<div class="kas-free-shipping-bar">
<span style="width:100%"></span>
</div>
</div>
<?php
return;
}
$remaining = max( 0, $limit - $subtotal );
$percent = min( 100, ( $subtotal / $limit ) * 100 );
?>
<div class="kas-free-shipping-wrap">
<div class="kas-free-shipping-text">
Add <strong><?php echo wc_price( $remaining ); ?></strong> more for Free Shipping
</div>
<div class="kas-free-shipping-bar">
<span style="width:<?php echo esc_attr( $percent ); ?>%"></span>
</div>
</div>
<?php
}
/* ---------- PAGE HOOKS ---------- */
add_action( 'woocommerce_single_product_summary', 'kas_render_free_shipping_bar', 25 );
add_action( 'woocommerce_before_cart', 'kas_render_free_shipping_bar' );
add_action( 'woocommerce_review_order_before_cart_contents', 'kas_render_free_shipping_bar', 5 );
/* ---------- AJAX FRAGMENTS (NOT ON CHECKOUT) ---------- */
add_filter( 'woocommerce_add_to_cart_fragments', function( $fragments ) {
if ( is_checkout() ) {
return $fragments;
}
ob_start();
kas_render_free_shipping_bar();
$fragments['.kas-free-shipping-wrap'] = ob_get_clean();
return $fragments;
});
/* ---------- AUTO REFRESH (PRODUCT + CART ONLY) ---------- */
add_action( 'wp_footer', function() {
if ( ! is_cart() && ! is_product() ) return;
?>
<script>
jQuery(function($){
$(document.body).on(
'added_to_cart removed_from_cart updated_cart_totals',
function(){
$(document.body).trigger('wc_fragment_refresh');
}
);
});
</script>
<?php
});
/* ---------- STYLES + DUPLICATE FIX ---------- */
add_action( 'wp_head', function() {
?>
<style>
.kas-free-shipping-wrap {
margin:12px 0;
padding:12px;
background:#f7f7f7;
border-radius:6px;
}
.kas-free-shipping-text {
font-size:14px;
font-weight:600;
margin-bottom:6px;
}
.kas-free-shipping-bar {
width:100%;
height:8px;
background:#ddd;
border-radius:50px;
overflow:hidden;
}
.kas-free-shipping-bar span {
display:block;
height:100%;
background:linear-gradient(90deg,#00b67a,#00d084);
transition:width .4s ease;
}
/* FIX DOUBLE BAR ON CHECKOUT */
.woocommerce-checkout .kas-free-shipping-wrap:not(:first-of-type) {
display:none !important;
}
</style>
<?php
});