Display Delivery Fee WooCommerce

User
display delivery options like
delivery fee – fee
before subtotal if no shiiping apply then show delivery frere
in woocommerce
Assistant
To display **“Delivery Fee”** before the subtotal in WooCommerce and show **“Delivery Free”** if no shipping methods apply, you can hook into WooCommerce's cart totals template.

### ✅ Final Output Example

Delivery Fee: ₹40

or

Delivery Free

### ✅ Steps to Implement:

Add the following code to your **child theme’s `functions.php`** or a custom plugin:

add_action('woocommerce_review_order_before_order_total', 'custom_display_delivery_fee');
add_action('woocommerce_cart_totals_before_order_total', 'custom_display_delivery_fee');

function custom_display_delivery_fee() {
    // Only run on cart/checkout page
    if (is_admin() && !defined('DOING_AJAX')) return;

    $packages = WC()->shipping()->get_packages();
    $delivery_fee = 0;
    $has_shipping = false;

    foreach ($packages as $package) {
        if (!empty($package['rates'])) {
            $has_shipping = true;
            foreach ($package['rates'] as $rate) {
                $delivery_fee += floatval($rate->cost);
            }
        }
    }

    echo '<tr class="delivery-fee">';
    echo '<th>Delivery Fee</th>';
    echo '<td>';

    if ($has_shipping && $delivery_fee > 0) {
        echo wc_price($delivery_fee);
    } else {
        echo '<strong>Delivery Free</strong>';
    }

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

### ✅ Result Placement

– **Cart Page:** Before subtotal
– **Checkout Page:** Before order total
– Uses shipping methods if defined
– Shows "Delivery Free" if no shipping rate applies (e.g. digital goods)

Let me know if you want it styled or conditional based on shipping zones or methods.

User
Its not calculating right
Assistant
Thanks for the update! Let's fix it so it **correctly calculates the actual selected shipping method cost** and displays "Delivery Free" only when **no shipping method applies or the cost is zero.**

### ✅ Revised and Accurate Version:

add_action('woocommerce_review_order_before_order_total', 'custom_display_delivery_fee');
add_action('woocommerce_cart_totals_before_order_total', 'custom_display_delivery_fee');

function custom_display_delivery_fee() {
    // Get the chosen shipping methods
    $chosen_methods = WC()->session->get('chosen_shipping_methods');
    $packages = WC()->shipping()->get_packages();
    $delivery_fee = 0;
    $has_shipping = false;

    if (!empty($packages) && is_array($packages)) {
        foreach ($packages as $i => $package) {
            if (!empty($package['rates']) && isset($chosen_methods[$i])) {
                $rate_id = $chosen_methods[$i];
                if (isset($package['rates'][$rate_id])) {
                    $delivery_fee += floatval($package['rates'][$rate_id]->cost);
                    $has_shipping = true;
                }
            }
        }
    }

    echo '<tr class="delivery-fee">';
    echo '<th>Delivery Fee</th>';
    echo '<td>';

    if ($has_shipping && $delivery_fee > 0) {
        echo wc_price($delivery_fee);
    } else {
        echo '<strong>Delivery Free</strong>';
    }

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

### 🔍 What’s Improved:
– Uses the **currently selected shipping method**, not just all available.
– Handles **multiple packages** (e.g., split shipping).
– Shows **“Delivery Free”** if there's no rate or rate is `0`.

Let me know if you want this:
– Hidden on free shipping.
– Styled or translated.
– Or to replace the actual shipping row instead of adding a new one.

User
also display shiping option name and deliver to ocation countrty
Assistant
Great — let's enhance the output to also:

– ✅ Show the **selected shipping method name**
– ✅ Show the **delivery destination country**
– ✅ Continue showing the fee (or "Delivery Free")

### ✅ Final Enhanced Code (Drop into `functions.php`):

add_action('woocommerce_review_order_before_order_total', 'custom_display_delivery_info');
add_action('woocommerce_cart_totals_before_order_total', 'custom_display_delivery_info');

function custom_display_delivery_info() {
    // Get shipping session data
    $chosen_methods = WC()->session->get('chosen_shipping_methods');
    $packages = WC()->shipping()->get_packages();
    $delivery_fee = 0;
    $shipping_method_name = '';
    $has_shipping = false;
    $country = WC()->customer->get_shipping_country();

    if (!empty($packages) && is_array($packages)) {
        foreach ($packages as $i => $package) {
            if (!empty($package['rates']) && isset($chosen_methods[$i])) {
                $rate_id = $chosen_methods[$i];
                if (isset($package['rates'][$rate_id])) {
                    $rate = $package['rates'][$rate_id];
                    $delivery_fee += floatval($rate->cost);
                    $shipping_method_name = $rate->get_label();
                    $has_shipping = true;
                }
            }
        }
    }

    // Display info before subtotal
    echo '<tr class="delivery-fee">';
    echo '<th>Delivery</th>';
    echo '<td>';

    if ($has_shipping) {
        echo esc_html($shipping_method_name) . ' — ';
        echo $delivery_fee > 0 ? wc_price($delivery_fee) : '<strong>Delivery Free</strong>';
    } else {
        echo '<strong>Delivery Free</strong>';
    }

    if ($country) {
        echo '<br><small>Deliver to: ' . WC()->countries->countries[$country] . '</small>';
    }

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

### 🧾 Example Output:

Delivery
Standard Shipping — ₹40
Deliver to: India

Or if free:

Delivery
Free Shipping — Delivery Free
Deliver to: Germany

### ✅ Works on:
– Cart page
– Checkout page
– Multi-package shipping (e.g., if plugins split items)

Let me know if you'd like:
– Flags next to country names
– Zip/postcode shown too
– Custom text for delivery message

User
MOve woocomerc coupon apply secton ti above the subtoal on checkout page
Assistant
To move the **"Have a coupon?"** section **above the subtotal on the WooCommerce checkout page**, you need to:

1. **Remove** the default coupon form.
2. **Re-insert** it in the location you want (above subtotal).

### ✅ Add this to your theme's `functions.php`:

// Remove coupon form from default position (above payment section)
remove_action('woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10);

// Add coupon form above subtotal
add_action('woocommerce_review_order_before_cart_contents', 'woocommerce_checkout_coupon_form');

### 📍 What this does:

– Moves the "Have a coupon?" toggle and form to just **above the subtotal** in the checkout summary (right column).
– Keeps all original coupon functionality.

### 📝 Optional: Style it for better spacing

You can add CSS to your theme or Customizer:

.woocommerce-form-coupon {
    margin-bottom: 20px;
    padding: 15px;
    background: #f7f7f7;
    border: 1px solid #ddd;
}

Let me know if you want the coupon field **always expanded**, or to customize the text ("Have a coupon?") as well.

User
create custom field for coupon and apply via ajax of exisiting coupon sectuon
Assistant
To **create a custom coupon input field** and apply it via **AJAX**, reusing WooCommerce’s existing coupon functionality, follow this clean and secure setup:

## ✅ What You'll Get

– A **custom coupon input field** (anywhere on checkout page).
– An **"Apply Coupon"** button.
– It works via **AJAX**, without reloading the page.
– Uses WooCommerce’s own validation system.

## 🔧 Step 1: Add Custom Coupon Field via Hook

Add this to your `functions.php`:

add_action('woocommerce_review_order_before_order_total', 'custom_coupon_field');

function custom_coupon_field() {
    ?>
    <tr class="custom-coupon-row">
        <th>Enter Coupon</th>
        <td>
            <input type="text" id="custom_coupon_code" placeholder="Enter coupon code" style="width: 60%;" />
            <button type="button" id="apply_custom_coupon" class="button">Apply</button>
            <p class="custom-coupon-message" style="margin-top:5px;"></p>
        </td>
    </tr>
    <?php
}

## 🔧 Step 2: Add AJAX Script (enqueue + logic)

Add to `functions.php`:

add_action('wp_footer', 'custom_coupon_ajax_script');

function custom_coupon_ajax_script() {
    if (!is_checkout()) return;
    ?>
    <script type="text/javascript">
    jQuery(function($) {
        $('#apply_custom_coupon').on('click', function() {
            var coupon_code = $('#custom_coupon_code').val();
            var $button = $(this);
            var $message = $('.custom-coupon-message');

            $button.prop('disabled', true);
            $message.text('Applying...');

            $.ajax({
                url: wc_checkout_params.ajax_url,
                type: 'POST',
                data: {
                    action: 'apply_custom_coupon',
                    coupon_code: coupon_code
                },
                success: function(response) {
                    if (response.success) {
                        $message.css('color', 'green').text(response.data.message);
                        $('body').trigger('update_checkout');
                    } else {
                        $message.css('color', 'red').text(response.data.message);
                    }
                },
                complete: function() {
                    $button.prop('disabled', false);
                }
            });
        });
    });
    </script>
    <?php
}

## 🧠 Step 3: Handle AJAX in PHP

Add to `functions.php`:

add_action('wp_ajax_apply_custom_coupon', 'handle_custom_coupon_ajax');
add_action('wp_ajax_nopriv_apply_custom_coupon', 'handle_custom_coupon_ajax');

function handle_custom_coupon_ajax() {
    $coupon_code = sanitize_text_field($_POST['coupon_code']);

    if (empty($coupon_code)) {
        wp_send_json_error(['message' => 'Please enter a coupon code.']);
    }

    WC()->cart->add_discount($coupon_code);

    if (WC()->cart->has_discount($coupon_code)) {
        wp_send_json_success(['message' => 'Coupon applied successfully!']);
    } else {
        wp_send_json_error(['message' => 'Invalid or expired coupon.']);
    }
}

## 🧪 Test It:
1. Add a product to cart.
2. Go to checkout.
3. Enter a valid coupon in the new field and hit “Apply”.
4. You should see a success or error message instantly, and the totals will update without page reload.

## ✅ Optional Enhancements:
– Auto-hide WooCommerce’s default coupon form.
– Auto-expand message field.
– Add spinner/loading indicator.

Let me know if you want to:
– Move the field elsewhere (e.g., top of checkout).
– Show it only if a product/category is in the cart.
– Add error logging or coupon usage limit notice.

User
placehodler not showing
Assistant
If the `placeholder` values are **not showing** in your custom WooCommerce billing fields rendering loop, it's likely because the `$field` array is missing the `'placeholder'` key — or it's being overridden.

### ✅ How to Fix It

WooCommerce uses the `'label'` as a placeholder **only when `'placeholder'` is not explicitly defined**.

Update your loop to **force the placeholder** from the label if it’s missing:

<div class="woocommerce-billing-fields__field-wrapper">
    <?php
    $fields = $checkout->get_checkout_fields('billing');

    foreach ($fields as $key => $field) {
        // If placeholder is missing, set it to label
        if (empty($field['placeholder']) && !empty($field['label'])) {
            $field['placeholder'] = $field['label'];
        }

        woocommerce_form_field($key, $field, $checkout->get_value($key));
    }
    ?>
</div>

### ✅ Bonus: Want placeholders only, no labels?

If you want to hide labels and show only placeholders:

$field['label'] = false;

Inside the loop:

foreach ($fields as $key => $field) {
    if (empty($field['placeholder']) && !empty($field['label'])) {
        $field['placeholder'] = $field['label'];
        $field['label'] = false; // Hide label if only using placeholder
    }

    woocommerce_form_field($key, $field, $checkout->get_value($key));
}

Let me know if you're customizing specific fields (like `billing_phone`, `billing_email`, etc.), and I can show you how to add placeholders just for those.

User
also copy same coupons sucess false message on cusotm oupon apply
Assistant
To **reuse WooCommerce’s native coupon success and error messages** (like the ones shown for the default coupon form) in your **custom AJAX coupon field**, follow this guide:

## ✅ Goal

– Use the **same messages** WooCommerce shows (like _"Coupon applied successfully."_ or _"Coupon does not exist!"_) in your custom field.

## 🔧 Update Your PHP AJAX Handler

Replace your existing `handle_custom_coupon_ajax()` function with this updated version:

add_action('wp_ajax_apply_custom_coupon', 'handle_custom_coupon_ajax');
add_action('wp_ajax_nopriv_apply_custom_coupon', 'handle_custom_coupon_ajax');

function handle_custom_coupon_ajax() {
    $coupon_code = isset($_POST['coupon_code']) ? wc_format_coupon_code(wp_unslash($_POST['coupon_code'])) : '';

    if (empty($coupon_code)) {
        wp_send_json_error(['message' => __('Please enter a coupon code.', 'woocommerce')]);
    }

    // Backup notices
    ob_start();
    WC()->cart->add_discount($coupon_code);
    wc_print_notices(); // Capture all WC notices
    $notices = ob_get_clean();

    // Check if coupon applied
    if (WC()->cart->has_discount($coupon_code)) {
        wp_send_json_success(['message' => $notices]);
    } else {
        wp_send_json_error(['message' => $notices]);
    }
}

## 🔧 Update Your JS Handler to Display WooCommerce-Style Message

Update the `success:` and `error:` part of your JS (from the previous answer) like this:

$message.html(response.data.message);

✅ Final JS Snippet:

jQuery(function($) {
    $('#apply_custom_coupon').on('click', function() {
        var coupon_code = $('#custom_coupon_code').val();
        var $button = $(this);
        var $message = $('.custom-coupon-message');

        $button.prop('disabled', true);
        $message.html('Applying...');

        $.ajax({
            url: wc_checkout_params.ajax_url,
            type: 'POST',
            data: {
                action: 'apply_custom_coupon',
                coupon_code: coupon_code
            },
            success: function(response) {
                $message.html(response.data.message);
                if (response.success) {
                    $('body').trigger('update_checkout');
                }
            },
            error: function() {
                $message.html('<div class="woocommerce-error">Unexpected error. Try again.</div>');
            },
            complete: function() {
                $button.prop('disabled', false);
            }
        });
    });
});

### 🎯 Result

– Uses the **exact WooCommerce-generated messages** (styled as `.woocommerce-error`, `.woocommerce-message`).
– Fully supports **translated strings** and **plugin-based enhancements**.

Let me know if you'd like the message to appear in the standard notice area (`woocommerce-notices-wrapper`) instead of below the input field.

User
on checkout page order review add quantity + – and change quantity
Assistant
To **add a quantity + / – button next to each product in the WooCommerce Checkout page (order review table)** and allow updating quantities via AJAX — follow this guide.

## ✅ What You’ll Achieve:

– Show `+` and `–` buttons for product quantities on the **checkout page**.
– Quantities will update via AJAX and update totals live (just like cart page).

## 🧩 Step-by-Step Implementation

### ✅ Step 1: Enable Quantity Inputs on Checkout

By default, WooCommerce does not show quantity input on the checkout page. We’ll add it manually.

Add this to your **child theme’s `functions.php`**:

add_filter('woocommerce_checkout_cart_item_quantity', 'custom_checkout_qty_inputs', 10, 3);

function custom_checkout_qty_inputs($product_quantity, $cart_item, $cart_item_key) {
    $_product = $cart_item['data'];

    if (!$_product->is_sold_individually()) {
        $product_quantity = woocommerce_quantity_input(
            array(
                'input_name'  => "cart[{$cart_item_key}][qty]",
                'input_value' => $cart_item['quantity'],
                'min_value'   => 0,
                'max_value'   => $_product->get_max_purchase_quantity(),
                'product_name' => $_product->get_name(),
            ),
            $_product,
            false
        );
    }

    return $product_quantity;
}

### ✅ Step 2: Trigger AJAX When Quantity Changes

WooCommerce doesn’t update cart on checkout by default when quantity is changed. Add this script to `functions.php`:

add_action('wp_footer', 'custom_checkout_qty_update_script');

function custom_checkout_qty_update_script() {
    if (!is_checkout()) return;
    ?>
    <script type="text/javascript">
        jQuery(function($) {
            $('body').on('change', 'input.qty', function() {
                var data = {
                    action: 'custom_update_checkout_qty',
                    security: '<?php echo wp_create_nonce("custom-qty-update"); ?>',
                    qty: $(this).val(),
                    cart_item_key: $(this).attr('name').match(/[(.*?)]/)[1]
                };

                $.post(wc_checkout_params.ajax_url, data, function(response) {
                    if (response.success) {
                        $('body').trigger('update_checkout');
                    }
                });
            });
        });
    </script>
    <?php
}

### ✅ Step 3: Handle the AJAX on Server Side

Add this in `functions.php`:

add_action('wp_ajax_custom_update_checkout_qty', 'custom_update_checkout_qty');
add_action('wp_ajax_nopriv_custom_update_checkout_qty', 'custom_update_checkout_qty');

function custom_update_checkout_qty() {
    check_ajax_referer('custom-qty-update', 'security');

    $cart_item_key = sanitize_text_field($_POST['cart_item_key']);
    $qty = (int) $_POST['qty'];

    if (isset(WC()->cart->cart_contents[$cart_item_key])) {
        WC()->cart->set_quantity($cart_item_key, $qty, true);
    }

    WC()->cart->calculate_totals();
    wp_send_json_success();
}

### ✅ Step 4 (Optional): Style the + / – Buttons

WooCommerce's `quantity_input` includes the `+` and `–` buttons if your theme supports it. Add this CSS if you need:

.woocommerce .quantity {
    display: flex;
    align-items: center;
}
.woocommerce .quantity input.qty {
    width: 60px;
    text-align: center;
}

### ✅ Final Result

– Customers can change product quantity directly on the **checkout page**.
– Quantity change will **trigger AJAX update** and refresh totals in real time.

Let me know if you'd like:
– A debounce to prevent spammy AJAX requests.
– Custom styles for the buttons.
– Support for **removing item** if quantity set to 0.

Leave a Comment

Your email address will not be published. Required fields are marked *