Seb G
Seb G

Reputation: 671

Remove shipping cost if custom checkbox is checked in WooCommerce Checkout

I am trying to set the price of shipping rates to $0.00 if a checkbox in the checkout fields is checked.

Current Attempt:

function no_shipping_for_own_ups($rates,$package) {
    foreach ($rates as $rate) {
        //Set the price
        $rate->cost = 0;
    }
    return $rates;
}

function woo_add_cart_ups_y_n_fee( $cart ){
    if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
        return;
    }

    if ( isset( $_POST['post_data'] ) ) {
        parse_str( $_POST['post_data'], $post_data );
    } else {
        $post_data = $_POST;
    }

    if (isset($post_data['billing_ups_yn'])) {
        add_filter( 'woocommerce_package_rates','no_shipping_for_own_ups', 99, 2 );
    }
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_ups_y_n_fee', 43, 1 );

As $post_data['billing_ups_yn'] being the checkbox that I set to update the checkout when triggered.

Simply if the checkbox is checked, then apply the filter to set shipping rates to 0.
This, however, isn't working.

Upvotes: 2

Views: 5476

Answers (2)

LoicTheAztec
LoicTheAztec

Reputation: 253921

To alter shipping methods cost via Ajax on a custom javascript event in checkout page is quiet more complicated than conditionally altering fees or anything else as you will see below.

To store the Ajax data I use WC_Sessions and to alter Shipping methods costs will only work if you manipulate the shipping sessions data

The full working code:

// Add a Custom checkbox field for shipping options (just for testing)
add_action( 'woocommerce_after_checkout_billing_form', 'custom_billing_checkbox_for_testing', 10, 1 );
function custom_billing_checkbox_for_testing( $checkout ) {
    $field_id = 'billing_ups_yn';

    // Get the checked state if exist
    $billing_ups = WC()->session->get('billing_ups' );
    if(empty($billing_ups))
        $billing_ups = $checkout->get_value( $field_id );

    // Add the custom checkout field (checkbox)
    woocommerce_form_field( $field_id, array(
        'type' => 'checkbox',
        'class' => array( 'form-row-wide' ),
        'label' => __('Billing UPS'),
    ), $billing_ups );
}

// function that gets the Ajax data
add_action( 'wp_ajax_woo_get_ajax_data', 'woo_get_ajax_data' );
add_action( 'wp_ajax_nopriv_woo_get_ajax_data', 'woo_get_ajax_data' );
function woo_get_ajax_data() {
    if ( $_POST['billing_ups'] == '1' ){
        WC()->session->set('billing_ups', '1' );
    } else {
        WC()->session->set('billing_ups', '0' );
    }
    echo json_encode( WC()->session->get('billing_ups' ) );
    die(); // Alway at the end (to avoid server error 500)
}

// Conditionally changing the shipping methods costs
add_filter( 'woocommerce_package_rates','conditional_custom_shipping_cost', 90, 2 );
function conditional_custom_shipping_cost( $rates, $package ) {

    if ( WC()->session->get('billing_ups' ) == '1' ){
        foreach ( $rates as $rate_key => $rate_values ) {
            // Not for "Free Shipping method" (all others only)
            if ( 'free_shipping' !== $rate_values->method_id ) {

                // Set the rate cost
                $rates[$rate_key]->cost = 0;

                // Set taxes rate cost (if enabled)
                $taxes = array();
                foreach ($rates[$rate_key]->taxes as $key => $tax)
                    if( $rates[$rate_key]->taxes[$key] > 0 ) // set the new tax cost
                        $taxes[$key] = 0;
                $rates[$rate_key]->taxes = $taxes;
            }
        }
    }
    return $rates;
}

// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
    $bool = true;
    if ( WC()->session->get('billing_ups' ) == '1' ) $bool = false;

    // Mandatory to make it work with shipping methods
    foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
        WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
    }
    WC()->cart->calculate_shipping();
}

// The Jquery script
add_action( 'wp_footer', 'custom_checkout_script' );
function custom_checkout_script() {
    ?>
    <script type="text/javascript">
        jQuery( function($){

            // update cart on delivery location checkbox option
            $('#billing_ups_yn_field input').change( function () {
                var checked = 0;
                if ( $('#billing_ups_yn').is(':checked') )
                    checked = 1;

                $.ajax({
                    type: 'POST',
                    url: wc_checkout_params.ajax_url,
                    data: {
                        'action': 'woo_get_ajax_data',
                        'billing_ups': checked,
                    },
                    success: function (result) {
                        $('body').trigger('update_checkout');
                        console.log('response: '+result); // just for testing
                    },
                    error: function(error){
                        console.log(error); // just for testing
                    }
                });
            });
        });
    </script>
    <?php
}

Code goes in function.php file of your active child theme (or active theme).

Tested and works.


Update related to your comment:

If you wish to have always the checkbox unchecked by default at load you will replace the first function by this one:

// Add a Custom checkbox field for shipping options (just for testing)
add_action( 'woocommerce_after_checkout_billing_form', 'custom_billing_checkbox_for_testing', 10, 1 );
function custom_billing_checkbox_for_testing( $checkout ) {
    $field_id = 'billing_ups_yn';

    // Add the custom checkout field (checkbox)
    woocommerce_form_field( $field_id, array(
        'type' => 'checkbox',
        'class' => array( 'form-row-wide' ),
        'label' => __('Billing UPS'),
    ), '' );
}

Upvotes: 6

silver
silver

Reputation: 5311

I have similar project about 3 years ago and has radio button and date picker that will both modify and update the shipping details/amount when changed, the radio button will modify Shipping surcharge and the date picker will have -10 discount price when Saturday and Friday is selected from the calendar.

working example here

I assume you had knowledge with PHP and AJax and can modify this, you only need to modify few things like the session value and calculation as well as those jquery selector and form fields selector

function to handle ajax request, the purpose is to only assign $_SESSION value

add_action('wp_ajax_woo_modify_charges', 'etq_calculate', 10);
add_action('wp_ajax_nopriv_woo_modify_charges', 'etq_calculate', 10);
function etq_calculate() {
    global $woocommerce;
    $charge = isset($_POST['billing_area']) ? $_POST['billing_area'] : 'no';
    $deldate = isset($_POST['jck_delivery_date']) ? $_POST['jck_delivery_date'] : '06/08/2015';
    $delday = strtotime(str_replace('/', '-', $deldate));
    $day = date('l', $delday);
    if ( $day === 'Saturday' || $day === 'Friday') $val = -10;
    else $val = 0;

    if ( $charge === 'no' ) $surchage = 0;
    else $surchage = 10; 

    if( !isset($_SESSION) ) session_start();
    $_SESSION['val'] = $val;
    $_SESSION['surcharge'] = $surchage;
}

Next function is to hook the modification on woocommerce_cart_calculate_fees from the value of $_SESSION.. this is where the price update happens

add_action('woocommerce_cart_calculate_fees', 'woo_change_cart_fee');
function woo_change_cart_fee() {
    if(!isset($_SESSION)) session_start();
    $surcharge = isset($_SESSION['surcharge']) ? $_SESSION['surcharge'] : 0;
    $discount = isset($_SESSION['val']) ? $_SESSION['val'] : 0;

    if ( $surcharge !== '0' ) WC()->cart->add_fee('Shipping Surchage', $surcharge, false, '');
    if ( $discount !== '0' ) WC()->cart->add_fee('Delivery Discount', $discount, false, '');
}

then for jquery script that handles ajax

(function($){
    'use strict';
    $(document).ready( function() { 

        var $date_field = $('#jck_delivery_date');

        // update cart on delivery date changes
        $('#jck_delivery_date').bind('change', function () {
                if ($('#billing_area_yes').is(':checked')) {
                    var surcharge = $('#billing_area_yes').val();
                    $('#billing_area_yes').prop('checked', true);
                } else {
                    var surcharge = 'no';
                }

                var deldate = $('#jck_delivery_date').val();
                var data = {
                    action: 'woo_modify_charges',
                    jck_delivery_date: deldate,
                    billing_area: surcharge
                };

                $.ajax({
                    type: 'POST',
                    url: wc_checkout_params.ajax_url,
                    data: data,
                    success: function (code) {
                        console.log(code);
                        //jQuery('.woocommerce-error, .woocommerce-message').remove();

                        if (code === '0') {
                            //$form.before(code);
                            $('body').trigger('update_checkout');
                        }
                    },
                    dataType: 'html'
                });

                return false;
        });

        // update cart on delivery location checkbox option
        $('#billing_area_field input').change( function () {
            if ($('#billing_area_yes').is(':checked')) {
                var surcharge = $('#billing_area_yes').val();
            } else {
                var surcharge = 'no';
            }
            var deldate = $('#jck_delivery_date').val();
            console.log( surcharge );
            var data = {
                action: 'woo_modify_charges',
                billing_area: surcharge,
                jck_delivery_date: deldate,
            };

            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: data,
                success: function (code) {
                    console.log(code);
                    //jQuery('.woocommerce-error, .woocommerce-message').remove();

                    if (code === '0') {
                        //$form.before(code);
                        $('body').trigger('update_checkout');
                    }
                },
                dataType: 'html'
            });

            return false;
        });
    });
})(jQuery);

Upvotes: 1

Related Questions