Display Delivery Fee WooCommerce
August 7, 2025 · AI Conversations
delivery fee – fee
before subtotal if no shiiping apply then show delivery frere
in woocommerce
### ✅ 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.
—
### ✅ 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.
– ✅ 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
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.
—
## ✅ 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.
—
### ✅ 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.
—
## ✅ 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.
—
## ✅ 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.