Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.8k views
in Technique[技术] by (71.8m points)

php - Move coupon form before payment section in WooCommerce checkout

I would like to move the coupon field at checkout to the woocommerce_review_order_before_payment hook.

Having the coupon field at the top of the page negatively affects conversions as users immediately try looking for a coupon code and abandon checkout if they fail to find one.

I read online that it's not that simple because the coupon field is also a form. And placing the coupon field anywhere inside the checkout form causes the "Apply Coupon" to submit the order form instead of applying the coupon.

I also read online that there are working solutions to fix this issue. But there are no tutorials on how to do it even though people have been asking this same question for years.

Could someone please give a step by step tutorial on how to properly move the coupon field and end this issue once and for all?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You could adapt something like Move coupon form before subtotal in WooCommerce checkout answer code, but it will not work for many reasons…

Revisited updated answer (simplified without Ajax, just like WooCommerce default one):

// Just hide default woocommerce coupon field
add_action( 'woocommerce_before_checkout_form', 'hide_checkout_coupon_form', 5 );
function hide_checkout_coupon_form() {
    echo '<style>.woocommerce-form-coupon-toggle {display:none;}</style>';
}


// Add a custom coupon field before checkout payment section
add_action( 'woocommerce_review_order_before_payment', 'woocommerce_checkout_coupon_form_custom' );
function woocommerce_checkout_coupon_form_custom() {
    echo '<div class="checkout-coupon-toggle"><div class="woocommerce-info">' . sprintf(
        __("Have a coupon? %s"), '<a href="#" class="show-coupon">' . __("Click here to enter your code") . '</a>'
    ) . '</div></div>';

    echo '<div class="coupon-form" style="margin-bottom:20px;" style="display:none !important;">
        <p>' . __("If you have a coupon code, please apply it below.") . '</p>
        <p class="form-row form-row-first woocommerce-validated">
            <input type="text" name="coupon_code" class="input-text" placeholder="' . __("Coupon code") . '" id="coupon_code" value="">
        </p>
        <p class="form-row form-row-last">
            <button type="button" class="button" name="apply_coupon" value="' . __("Apply coupon") . '">' . __("Apply coupon") . '</button>
        </p>
        <div class="clear"></div>
    </div>';
}

// jQuery code
add_action( 'wp_footer', 'custom_checkout_jquery_script' );
function custom_checkout_jquery_script() {
    if ( is_checkout() && ! is_wc_endpoint_url() ) :
    ?>
    <script type="text/javascript">
    jQuery( function($){
        $('.coupon-form').css("display", "none"); // Be sure coupon field is hidden
        
        // Show or Hide coupon field
        $('.checkout-coupon-toggle .show-coupon').on( 'click', function(e){
            $('.coupon-form').toggle(200);
            e.preventDefault();
        })
        
        // Copy the inputed coupon code to WooCommerce hidden default coupon field
        $('.coupon-form input[name="coupon_code"]').on( 'input change', function(){
            $('form.checkout_coupon input[name="coupon_code"]').val($(this).val());
            // console.log($(this).val()); // Uncomment for testing
        });
        
        // On button click, submit WooCommerce hidden default coupon form
        $('.coupon-form button[name="apply_coupon"]').on( 'click', function(){
            $('form.checkout_coupon').submit();
            // console.log('click: submit form'); // Uncomment for testing
        });
    });
    </script>
    <?php
    endif;
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.


Original first answer:

You will need something completely custom, to be able to make work a coupon input field just before checkout payment section. It additionally requires Ajax and jQuery code as follows:

// Remove default coupon field
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10 );

// Add a custom coupon field before checkout payment section
add_action( 'woocommerce_review_order_before_payment', 'woocommerce_checkout_coupon_form_custom' );
function woocommerce_checkout_coupon_form_custom() {
    echo '<div class="coupon-form" style="margin-bottom:20px;">
        <p>' . __("If you have a coupon code, please apply it below.") . '</p>
        <p class="form-row form-row-first woocommerce-validated">
            <input type="text" name="coupon_code" class="input-text" placeholder="' . __("Coupon code") . '" id="coupon_code" value="">
        </p>
        <p class="form-row form-row-last">
            <button type="button" class="button" name="apply_coupon" value="' . __("Apply coupon") . '">' . __("Apply coupon") . '</button>
        </p>
        <div class="clear"></div>
    </div>';
}

// jQuery - Send Ajax request
add_action( 'wp_footer', 'custom_checkout_jquery_script' );
function custom_checkout_jquery_script() {
    if ( is_checkout() && ! is_wc_endpoint_url() ) :
    ?>
    <script type="text/javascript">
    jQuery( function($){
        if (typeof wc_checkout_params === 'undefined')
            return false;

        var couponCode = '';

        $('input[name="coupon_code"]').on( 'input change', function(){
            couponCode = $(this).val();
        });

        $('button[name="apply_coupon"]').on( 'click', function(){
            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action': 'apply_checkout_coupon',
                    'coupon_code': couponCode,
                },
                success: function (response) {
                    $(document.body).trigger("update_checkout"); // Refresh checkout
                    $('.woocommerce-error,.woocommerce-message').remove(); // Remove other notices
                    $('input[name="coupon_code"]').val(''); // Empty coupon code input field
                    $('form.checkout').before(response); // Display notices
                    // console.log(response); // Uncomment for testing
                }
            });
        });
    });
    </script>
    <?php
    endif;
}

// Ajax receiver function
add_action( 'wp_ajax_apply_checkout_coupon', 'apply_checkout_coupon_ajax_receiver' );
add_action( 'wp_ajax_nopriv_apply_checkout_coupon', 'apply_checkout_coupon_ajax_receiver' );
function apply_checkout_coupon_ajax_receiver() {
    if ( isset($_POST['coupon_code']) && ! empty($_POST['coupon_code']) ) {
        WC()->cart->add_discount( wc_format_coupon_code( wp_unslash( $_POST['coupon_code'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    } else {
        wc_add_notice( WC_Coupon::get_generic_coupon_error( WC_Coupon::E_WC_COUPON_PLEASE_ENTER ), 'error' );
    }
    wc_print_notices();
    wp_die();
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...