2

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);
            }
        });  
        
    });
Dillon L.
  • 45
  • 5

1 Answers1

3

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);
},
Josh Bonnick
  • 2,281
  • 1
  • 10
  • 21
  • This helped tremendously, I was curious do you happen to know with the given jquery right at where we establish the var coupon, why on my payload in the request via admin-ajax why it is sending literally coupon as the value on click? is there another way to have the var data grab the coupon_code ? – Dillon L. Feb 10 '22 at 00:36
  • I didn't notice that... you just need to remove the string wrappers around it... so it would be `coupon_code : coupon` and then the variable value of coupon will be sent to the server. Also, you should clean the input on the server, just incase, `sanitize_text_field($_POST['coupon_code']);` it will strip malicious content and then you interact with the cleaned data. – Josh Bonnick Feb 10 '22 at 15:11
  • 1
    Josh I cannot thank you enough, I knew the answer was right in my face but I work solo so sometimes I need some other eyes :) – Dillon L. Feb 10 '22 at 16:50
  • No worries! You can also use the `ob_start` 'content' `ob_get_clean` any where you need to use `get_template_part` in an Ajax response, really useful as WordPress out of the box, as of right now, doesn't provide a way to get template parts as strings. – Josh Bonnick Feb 10 '22 at 18:38
  • This is good information! Still trying to figure out why its passing a value of 0 after removing double quotes, I think its because something im doing when obtaining the var coupon = jquery( 'input#minicart-coupon'.val(); – Dillon L. Feb 10 '22 at 21:50
  • addition to above comment, so it works beautifully on mobile -- but on DT it does not capture the value of the input, I haven't seen this behavior before and am thinking its the elementor mobile friendly version that is taking precedence? not 100% on it – Dillon L. Feb 11 '22 at 00:07