1

I have a little problem on WooCommerce using Avada theme: I want to display a field one time, even if there are multiple products, and calculate the price one time.

See the details are below...

Here is Avada theme review-order.php partial file:

<?php

do_action( 'woocommerce_review_order_before_cart_contents' );

    foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
        $_product     = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
        $product_id   = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
        $product_name = apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key );

        // Output the product name.
        echo '<h4>' . esc_html( $product_name ) . '</h4>';

        // Output the liftgate field.
        woocommerce_form_field( 'liftgate_' . $cart_item_key, array(
            'type'  => 'checkbox',
            'class' => array( 'form-row-wide' ),
            'label' => 'Add Liftgate ($90)',
        ), '');

        // Output the inside delivery field.
        woocommerce_form_field( 'inside_delivery_' . $cart_item_key, array(
            'type'  => 'checkbox',
            'class' => array( 'form-row-wide' ),
            'label' => 'Add Inside Delivery ($135)',
        ), '');
    }

    do_action( 'woocommerce_review_order_after_cart_contents' );

Here is my related code in y theme's functions.php file:

function calculate_additional_fees( $cart ) {
    $liftgate_fee = 90;
    $inside_delivery_fee = 135;

    $liftgate_total = 0;
    $inside_delivery_total = 0;

    // Loop through cart items
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        if ( isset( $_POST['liftgate_' . $cart_item_key] ) && $_POST['liftgate_' . $cart_item_key] == 1 ) {
            $liftgate_total += $liftgate_fee;
        }

        if ( isset( $_POST['inside_delivery_' . $cart_item_key] ) && $_POST['inside_delivery_' . $cart_item_key] == 1 ) {
            $inside_delivery_total += $inside_delivery_fee;
        }
    }

    // Add liftgate fee
    if ( $liftgate_total > 0 ) {
        $cart->add_fee( 'Liftgate', $liftgate_total );
    }

    // Add inside delivery fee
    if ( $inside_delivery_total > 0 ) {
        $cart->add_fee( 'Inside Delivery', $inside_delivery_total );
    }
}
add_action( 'woocommerce_cart_calculate_fees', 'calculate_additional_fees', 20, 1 );

How could I fix those issues.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399

1 Answers1

0

To allow 2 custom fees calculated on cart items count triggered by 2 unique checkboxes, requires something much more complex powered by Ajax and session variables...

First, you should restore the original template file, removing those 2 custom fields from your Avada theme customized review-order.php file.

Based on this similar thread here is the code:

// Add a custom radio fields for packaging selection
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_form_delivery_addition', 20 );
function checkout_shipping_form_delivery_addition(){
    $domain = 'wocommerce';

    echo '<tr class="delivery-checkbox"><th>' . __('Delivery options (per item)', $domain) . '</th><td>';

    // Get delivery options data from WooCommerce Session variable
    $delivery_fees = WC()->session->get('delivery_options');
    
    $chosen_liftgate     = isset($delivery_fees['liftgate']) && $delivery_fees['liftgate'] ? true : false;
    $chosen_ins_delivery = isset($delivery_fees['ins_delivery']) && $delivery_fees['ins_delivery'] ? true : false;

    // Output the liftgate field.
    woocommerce_form_field( 'liftgate', array(
        'type'  => 'checkbox',
        'class' => array( 'form-row-wide' ),
        'label' => __('Liftgate ($90)', $domain),
    ), $chosen_liftgate);

    // Output the inside delivery field.
    woocommerce_form_field( 'ins_delivery', array(
        'type'  => 'checkbox',
        'class' => array( 'form-row-wide' ),
        'label' => __('Inside Delivery ($135)', $domain),
    ), $chosen_ins_delivery);

    echo '</td></tr>';
}

// PHP: Remove "(optional)" from our non required fields
add_filter( 'woocommerce_form_field' , 'remove_checkout_optional_fields_label', 10, 4 );
function remove_checkout_optional_fields_label( $field, $key, $args, $value ) {
    // Only on checkout page
    if( is_checkout() && ! is_wc_endpoint_url() && ( 'liftgate' === $key || 'inside_delivery' === $key )) {
        $optional = '&nbsp;<span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
        $field = str_replace( $optional, '', $field );
    }
    return $field;
}

// jQuery - Ajax script
add_filter( 'wp_footer' , 'checkout_delivery_script' );
function checkout_delivery_script() {
    // Only on checkout page
    if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;
    
    // WC()->session->__unset('delivery_options'); // Reset 'delivery_options' session variable

    $optional = '&nbsp;<span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
    ?>
    <script>
    jQuery(function($){
        if (typeof wc_checkout_params === 'undefined')
            return false;
            
        // On "update" checkout form event Remove "(optional)" from our custom checkbox fields
        $(document.body).on('update_checkout', function(){
            $('#liftgate_field label > .optional').remove();
            $('#inside_delivery_field label > .optional').remove();
        });
        
        // Ajax 
        $('form.checkout').on('change', '.delivery-checkbox input', function(e){
            //e.preventDefault();
            var iSchecked = $(this).is(":checked") ? 1 : 0,
                fieldKey = e.target['name'];
            
            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action':     'delivery_options',
                    'is_checked': iSchecked,
                    'field_slug': fieldKey,
                },
                success: function (result) {
                    $('body').trigger('update_checkout');
                    console.log(result); // just for testing | TO BE REMOVED
                },
                error: function(error){
                    console.log(error); // just for testing | TO BE REMOVED
                }
            });
        });
    });
    </script>
    <?php
}

// Get Ajax request and saving to WC session
add_action( 'wp_ajax_delivery_options', 'wc_get_delivery_options_data' );
add_action( 'wp_ajax_nopriv_delivery_options', 'wc_get_delivery_options_data' );
function wc_get_delivery_options_data() {
    if ( isset($_POST['is_checked']) && isset($_POST['field_slug']) ){
        // Get delivery options from WooCommerce Session variable
        $delivery_options = WC()->session->get('delivery_options');
        
        // Initializing if empty
        if ( empty($delivery_options) ) {
            $delivery_options = array( 'liftgate' => 0,  'ins_delivery' => 0 );
        }
        
        // Sanitizing data
        $field_slug = sanitize_key( $_POST['field_slug'] );
        $is_checked = $_POST['is_checked'] ? '1' : '0';
        
        // Set new data to the data array
        $delivery_options[$field_slug] = $is_checked;
        
        // Updating delivery options WooCommerce Session variable
        WC()->session->set('delivery_options', $delivery_options );
        
        echo json_encode( $delivery_options ); // Return the value to jQuery
    }
    die();
}

// Calculate delivery option Fees dynamically
add_action( 'woocommerce_cart_calculate_fees', 'calculate_additional_fees', 20, 1 );
function calculate_additional_fees( $cart ) {
    // Only on checkout page
    if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;
    
    // Items count
    $cart_items_count = count($cart->get_cart()); // count by cart items
    // $cart_items_count = $cart->get_cart_contents_count(); // count by total cart items quantity
 
    // Fee costs by item
    $liftgate_fee = 90;
    $inside_delivery_fee = 135;
    
    // Get delivery options from WooCommerce Session variable
    $delivery_options = WC()->session->get('delivery_options');

    // Add liftgate fee
    if ( isset($delivery_options['liftgate']) && $delivery_options['liftgate'] ) {
        $cart->add_fee( __('Liftgate'), $liftgate_fee * $cart_items_count );
    }

    // Add inside delivery fee
    if ( isset($delivery_options['ins_delivery']) && $delivery_options['ins_delivery'] ) {
        $cart->add_fee( __('Inside Delivery'), $inside_delivery_fee * $cart_items_count );
    }
}

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

enter image description here

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399