Question

EDIT: see solution below from @motivast. With his basic setup you can then make whatever changes you'd like to specific auto-scroll actions and relocate whichever specific notices you want. My final solution also includes hooking a blank div within the coupon form and then targeting the coupon notices there, like this:

/* Add div to hook coupon notices to */
add_action ('woocommerce_cart_coupon' , 'coupon_notices_div' , 1 );
function coupon_notices_div() {
    echo "";
?>
<div class="cart-coupon-notices"></div>
<?php
}

With that in your custom plugin php file, you can then use .cart-coupon-notices instead of .cart-collaterals in @motivast's solution. This places the coupon notices immediately below the "apply coupon" button.


Original question:

I've found many examples of how to do this for the "added to cart" notice on products/shop pages, but the cart page seems to be altogether different. The notices I want to move more than any others are the coupon notices (i.e. "coupon applied successfully" etc.). Auto-scrolling the customers to the top of the page when they add a coupon is quite annoying for them.

The solution everyone talks about is that you need to just relocate wc_print_notices from the top of the cart page to somewhere else (I want it hooked to woocommerce_before_cart_totals), but no matter what I do the notices are still at the top of the page.

There are several variations of this question on stackexchange, none with any answers that work.

I've tried all the options listed here, but no luck.

I've tried playing with variations from here, also no luck.

I've tried the options from here, and... no luck.

Other variations of the same problem: here, here, a possible solution that works only with the storefront theme here.

Any help would be hugely appreciated!

EDIT: Two threads from elsewhere helping to solve this issue:

https://wordpress.org/support/topic/relocate-coupon-notices-on-cart-page/

https://www.facebook.com/groups/advanced.woocommerce/permalink/2141163449231396/

Was it helpful?

Solution

Coupon notices are displayed by updating cart dynamically using JavaScript. Moving wc_print_notices function will not take effect because all logic is placed in the cart.js file. You have to deregister and dequeue WooCommerce cart.js file and add your own modified version.

/**
 * Deregister and dequeue WooCommerce cart.js file and add own modified version.
 */
function wpse_305939_replace_woocommerce_cart_script() {

    /**
     * Remove default woocommerce cart scripts.
     */
    wp_deregister_script( 'wc-cart' );
    wp_dequeue_script( 'wc-cart' );

    /**
     * Add own modify scripts.
     */
    wp_register_script( 'wc-cart', plugin_dir_url( __FILE__ ) . 'js/cart.js', array( 'jquery', 'woocommerce', 'wc-country-select', 'wc-address-i18n' ), WC_VERSION, true );

    if( is_cart() ) {
        wp_enqueue_script( 'wc-cart' );
    }
}

add_action( 'wp_enqueue_scripts', 'wpse_305939_replace_woocommerce_cart_script', 20 );

Copy original cart.js entirely to your custom cart.js and update two methods.

apply_coupon

/**
 * Apply Coupon code
 *
 * @param {JQuery Object} $form The cart form.
 */
apply_coupon: function( $form ) {
    block( $form );

    var cart = this;
    var $text_field = $( '#coupon_code' );
    var coupon_code = $text_field.val();

    var data = {
        security: wc_cart_params.apply_coupon_nonce,
        coupon_code: coupon_code
    };

    $.ajax( {
        type:     'POST',
        url:      get_url( 'apply_coupon' ),
        data:     data,
        dataType: 'html',
        success: function( response ) {
            $( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
            show_notice( response, $('.cart-collaterals') );
            $( document.body ).trigger( 'applied_coupon', [ coupon_code ] );
        },
        complete: function() {
            unblock( $form );
            $text_field.val( '' );
            cart.update_cart( true, false);
        }
    } );
}

and update_cart

/**
 * Update entire cart via ajax.
 */
update_cart: function( preserve_notices, scroll_to_notices ) {
    var $form = $( '.woocommerce-cart-form' );

    block( $form );
    block( $( 'div.cart_totals' ) );

    // Make call to actual form post URL.
    $.ajax( {
        type:     $form.attr( 'method' ),
        url:      $form.attr( 'action' ),
        data:     $form.serialize(),
        dataType: 'html',
        success:  function( response ) {
            update_wc_div( response, preserve_notices );
        },
        complete: function() {

            scroll_to_notices = typeof scroll_to_notices !== 'undefined' ? scroll_to_notices : true;

            unblock( $form );
            unblock( $( 'div.cart_totals' ) );

            if( scroll_to_notices ) {
                $.scroll_to_notices( $( '[role="alert"]' ) );
            }
        }
    } );
}

You can check what has been updated comparing these two methods with an original cart.js file (WooCommerce 3.4.2).

This solution works only for notice when a coupon is applied.

OTHER TIPS

Building on the answer by @kierzniak I implemented a solution that would add the coupon notice to a modal dialog. The reason being that for the life of me I couldn't figure out how to retain the notice in the form when update_cart was run in the cart.js. This would effectively clear and repopulate any elements inside the form, including the proposed cart-coupon-notices div with it's notice content suggested by the OP. I'm also only showing the spinner in the coupon section as a double spinner just isn't good for anyone.

apply_coupon

/**
         * Apply Coupon code
         *
         * @param {JQuery Object} $form The cart form.
         */
        apply_coupon: function( $form ) {
            // block( $form );
             block ( $( '.cart-collaterals' ) ) ;

            var cart = this;
            var $text_field = $( '#coupon_code' );
            var coupon_code = $text_field.val();

            var data = {
                security: wc_cart_params.apply_coupon_nonce,
                coupon_code: coupon_code
            };

            $.ajax( {
                type:     'POST',
                url:      get_url( 'apply_coupon' ),
                data:     data,
                dataType: 'html',
                success: function( response ) {
                    $( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
                    jQuery(".cart-promo-notices").dialog({
                        autoOpen: false,
                        dialogClass: "cart-promo-dialog",
                        modal: true,
                        open: function(event, ui) {
                            jQuery("body").bind("click", function(event, ui) {
                                jQuery(".cart-promo-notices").dialog("close");
                            });
                        },

                    });
                    show_notice( response, $('.cart-promo-notices') );
                        $( document.body ).trigger( 'applied_coupon', [ coupon_code ] );
                },
                complete: function(  ) {
                    // unblock( $form );
                    unblock ( $( '.cart-collaterals' ) ) ;
                    $(".cart-promo-notices").dialog("open");
                    $text_field.val( '' );
                    cart.update_cart( true, false);
                }
            } );
        }

I added my div to the bottom of my cart.php in my WooCommerce override files in my theme

<div class="cart-promo-notices"></div>

Hide spinner in cart form

.woocommerce-cart-form .blockUI.blockOverlay { 
    display: none !important;
   }
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top