Search code examples
ajaxwordpresswoocommercewoocommerce-themingminicart

Woocommerce mini-cart ajax apply coupon


I have been going in circles with this I have added an apply coupon field to mini-cart.php and am trying to get it to run without refreshing the whole page. Any suggestions would be amazing help.

functions:

function apply_coupon_code(){
    $coupon_code = isset( $_POST["coupon_code"] ) ? $_POST["coupon_code"] : '';
    WC()->cart->apply_coupon($coupon_code);
}
add_action( 'wp_ajax_apply_coupon_code', 'apply_coupon_code' );
add_action( 'wp_ajax_nopriv_apply_coupon_code', 'apply_coupon_code' );

Input:

<?php if (empty (WC()->cart->get_coupons())): ?>
<span id="coupon-form">
<?php if ( wc_coupons_enabled() ) { ?>
    
        <form class="widget_shopping_cart_content" action="<?php echo $cart_url ?>" method="post">
            <?php } else { ?>
        <form id="apply-promo-code" class="widget_shopping_cart__coupon">
            <?php } ?>
            <label id="promo-code" for="coupon-code">Promo Code:</label>
                <input id="minicart-coupon" class="input-text" type="text" value="" name="coupon_code"/>
                    <button type="submit" id="minicart-apply-button" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?>"><?php esc_attr_e( 'Apply', 'woocommerce' ); ?></button>
                    <?php do_action( 'woocommerce_cart_coupon' ); ?>
                    <?php do_action( 'woocommerce_cart_actions' ); ?>
            </form>
            <?php endif; ?>
<?php foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
    <span id="widget-shopping-cart-remove-coupon" class="mini_cart_coupon-<?php echo esc_attr( sanitize_title( $code ) ); ?>">
        Promo Code: <?php echo esc_attr( sanitize_title( $code ) ); ?>

            <?php $remove_url = $cart_url.'?remove_coupon='.$coupon->code; ?> 
            <?php wc_cart_totals_coupon_html( $coupon ); ?>
    </span>
<?php endforeach; ?>            

jQuery:

    jQuery(document).on('click', 'button#minicart-apply-button', function() {
        
        var coupon = jQuery( 'input#minicart-coupon' ).val();
        var button = ( this );
        var data = {
            action: "apply_coupon_code",
            coupon_code: "coupon"
        };
    
       jQuery.ajax({
        type: 'POST',
        dataType: 'json',
        url: wc_add_to_cart_params.ajax_url,
        data: data,
        success: function (response) {
                console.log(response);
            },
            error: function (errorThrown) {
                console.log(errorThrown);
            }
        });  
        
    });

Solution

  • You can get the new mini cart HTML inside your ajax callback on the server and then return that as a response to the jQuery ajax call then simply replace the whole mini cart HTML on the front-end with the updated HTML.

    function apply_coupon_code(){
        $coupon_code = isset( $_POST["coupon_code"] ) ? $_POST["coupon_code"] : '';
        WC()->cart->apply_coupon($coupon_code);
        ob_start();
        woocommerce_mini_cart();
        $cart_html = ob_get_clean();
        return $cart_html;
    }
    add_action( 'wp_ajax_apply_coupon_code', 'apply_coupon_code' );
    add_action( 'wp_ajax_nopriv_apply_coupon_code', 'apply_coupon_code' );
    

    The output buffer is used here as woocommerce_mini_cart uses wc_get_template which just echoes out the content. The output buffer will allow you to capture this as a string.

    Now you need to tell jQuery that you're expecting HTML back from the server...

    jQuery(document).on('click', 'button#minicart-apply-button', function() {
        var coupon = jQuery( 'input#minicart-coupon' ).val();
        var button = ( this );
        var data = {
            action: "apply_coupon_code",
            coupon_code: "coupon"
        };
        
        jQuery.ajax({
            type: 'POST',
            dataType: 'html',
            url: wc_add_to_cart_params.ajax_url,
            data: data,
            success: function (response) {
                    console.log(response);
             },
            error: function (errorThrown) {
                    console.log(errorThrown);
            }
        });  
    });
    

    Now response will have the new HTML for the mini-cart, so you can replace it using jQuery's html() function...

    success: function (response) {
        console.log(response);
        jQuery('.mini-cart-wrapper').html(response);
    },