Add a Checkout Checkbox Field That Enable a Percentage Fee in Woocommerce

Add a WooCommerce checkout checkbox field that enable a discount based on product quantity

To determine the discount based on the number of items in the cart, you can use WC()->cart->get_cart_contents_count();

Which then can be applied in the woocommerce_cart_calculate_fees action hook.

So you get:

// Add a custom checkbox fields after billing fields
function action_woocommerce_after_checkout_billing_form( $checkout ) {
// Add a custom checkbox field
woocommerce_form_field( 'discount30', array(
'type' => 'checkbox',
'label' => __( ' Senior', 'woocommerce' ),
'class' => array( 'form-row-wide' ),
), '' );
}
add_action( 'woocommerce_after_checkout_billing_form', 'action_woocommerce_after_checkout_billing_form', 10, 1 );

// Remove "(optional)" label on "discount30" field
function filter_woocommerce_form_field( $field, $key, $args, $value ) {
// Only on checkout page
if ( $key === 'discount30' && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}

return $field;
}
add_filter( 'woocommerce_form_field' , 'filter_woocommerce_form_field', 10, 4 );

// jQuery - Ajax script
function action_wp_footer() {
// Only on Checkout
if ( is_checkout() && ! is_wc_endpoint_url() ) :

if ( WC()->session->__isset('enable_fee') )
WC()->session->__unset('enable_fee')
?>
<script type="text/javascript">
jQuery( function($){
if ( typeof wc_checkout_params === 'undefined' )
return false;

$( 'form.checkout' ).on( 'change', 'input[name=discount30]', function(e) {
var fee = $(this).prop('checked') === true ? '1' : '';

$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'enable_fee',
'enable_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer' );

// Get Ajax request and saving to WC session
function get_enable_fee() {
if ( isset($_POST['enable_fee']) ) {
WC()->session->set( 'enable_fee', ( $_POST['enable_fee'] ? true : false ) );
}
die();
}
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );

// Add a custom 3 Cents Discount
function action_woocommerce_cart_calculate_fees( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;

// Get number of items in the cart.
$items_in_cart = $cart->get_cart_contents_count();

// Calculate
$discount = 0.03 * $items_in_cart;

// Apply discount
if ( WC()->session->get('enable_fee') ) {
$cart->add_fee( __( 'Discount', 'woocommerce' ), -$discount );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );

Note: to get the number of products in cart opposite the number of items in cart

Change

// Get number of items in the cart.
$items_in_cart = $cart->get_cart_contents_count();

// Calculate
$discount = 0.03 * $items_in_cart;

To

// Products in cart
$products_in_cart = count( $cart->get_cart() );

// Calculate
$discount = 0.03 * $products_in_cart;

Display a checkbox that add a fee in Woocommerce checkout page

You really need to use Wordpress Ajax with WC_sessions to make it work like in "Add a checkout checkbox field that enable a percentage fee in Woocommerce" answer thread.

Here is your revisited code:

// Display the custom checkbow field in checkout
add_action( 'woocommerce_review_order_before_order_total', 'fee_installment_checkbox_field', 20 );
function fee_installment_checkbox_field(){
echo '<tr class="packing-select"><th>';

woocommerce_form_field( 'installment_fee', array(
'type' => 'checkbox',
'class' => array('installment-fee form-row-wide'),
'label' => __('Support installation'),
'placeholder' => __(''),
), WC()->session->get('installment_fee') ? '1' : '' );

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

// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :

if( WC()->session->__isset('installment_fee') )
WC()->session->__unset('installment_fee')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;

$('form.checkout').on('change', 'input[name=installment_fee]', function(){
var fee = $(this).prop('checked') === true ? '1' : '';

$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'installment_fee',
'installment_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}

// Get Ajax request and saving to WC session
add_action( 'wp_ajax_installment_fee', 'get_installment_fee' );
add_action( 'wp_ajax_nopriv_installment_fee', 'get_installment_fee' );
function get_installment_fee() {
if ( isset($_POST['installment_fee']) ) {
WC()->session->set('installment_fee', ($_POST['installment_fee'] ? true : false) );
}
die();
}

// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_installment_fee' );
function set_installment_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') || ! is_checkout() )
return;

if ( did_action('woocommerce_cart_calculate_fees') >= 2 )
return;

if ( 1 == WC()->session->get('installment_fee') ) {
$items_count = WC()->cart->get_cart_contents_count();
$fee_label = sprintf( __( "Support installation %s %s" ), '×', $items_count );
$fee_amount = 50000 * $items_count;
WC()->cart->add_fee( $fee_label, $fee_amount );
}
}

add_filter( 'woocommerce_form_field' , 'remove_optional_txt_from_installment_checkbox', 10, 4 );
function remove_optional_txt_from_installment_checkbox( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'installment_fee' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}

Code goes in functions.php file of your active child theme (or active theme). Tested and works on Woocommerce version 3.6.5 with Storefront theme.

Checkbox enabling a percentage discount in WooCommerce Checkout for specific category

Update 3

Use the following revisited code with an additional custom conditional function that check if items are only from specific product categories and can also give the non discounted subtotal for the items from your specific product category(ies).

You will have to set in that function your correct product category(ies) in the array and you can use term name(s), slug(s) or Id(s).

The subtotal is now calculated only for items from your specific product category for the discount and it's a non discounted subtotal, so you don't need to hide anymore the coupon field.

The checkbox is displayed when there is at least an item from your specific product category.

// Custom conditional function that check for specific product categories (and calculate their subtotal)
function check_cart_items_for_specific_categories( $type = 'boolean') {
$categories = array('online-seminars'); // <=== Here define your product category (name, slug or Id)
$category_found = false; // Initializing
$item_subtotal = 0; // Initializing

foreach( WC()->cart->get_cart() as $item ) {
if ( has_term( $categories, 'product_cat', $item['product_id'] ) ) {
$category_found = true;
$item_subtotal += $item['line_total'];
}
}

if ( $type === 'subtotal' ) {
return $item_subtotal;
} else {
return $category_found;
}
}

// Add a custom checkbox fields after billing fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_custom_checkout_checkbox', 20 );
function add_custom_checkout_checkbox(){
if( ! check_cart_items_for_specific_categories() ) return; // Exit

// Add a custom checkbox field
woocommerce_form_field( 'student_discount_fee', array(
'type' => 'checkbox',
'label' => __(' Yes, I am a student lawyer studying law'),
'class' => array( 'form-row-wide' ),
), '' );
}

// Remove "(optional)" label on "Student discount checkbox" field
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'student_discount_fee' === $key && is_checkout() && check_cart_items_for_specific_categories() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}

// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() && check_cart_items_for_specific_categories() ) :

if( WC()->session->__isset('enable_fee') )
WC()->session->__unset('enable_fee')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;

$('form.checkout').on('change', 'input[name=student_discount_fee]', function() {
var fee = $(this).prop('checked') === true ? '1' : '';

$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action' : 'enable_fee',
'enable_fee': fee,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}

// Get Ajax request and saving to WC session
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );
function get_enable_fee() {
if ( isset($_POST['enable_fee']) ) {
WC()->session->set('enable_fee', ($_POST['enable_fee'] ? true : false) );
}
die();
}

// Add a custom dynamic 15% fee
add_action( 'woocommerce_cart_calculate_fees', 'custom_percentage_fee', 20, 1 );
function custom_percentage_fee( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;

if( WC()->session->get('enable_fee') && check_cart_items_for_specific_categories() ) {
$percentage = -33.33333333333333; // Set the percentage discount (negative float number)
$subtotal = check_cart_items_for_specific_categories('subtotal'); // Related items subtotal
$discount = $subtotal * $percentage / 100;

$cart->add_fee( strtoupper( __( 'Student lawyer discount', 'woocommerce') ), $discount );
}
}

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

Calculate fee from cart totals (subtotal + shipping) without adding it to order total value in WooCommerce

Since you don't want to add it to the total, you can add a custom table row to the woocommerce-checkout-review-order-table instead of a cart fee. So my answer is not based on the WooCommerce fee and is completely separate from it.

The custom table row will then show/hide the percentage, based on if the checkbox is checked.

Explanation via one-line comments, added to my answer.

So you get:

// Add checkbox field
function action_woocommerce_before_order_notes( $checkout ) {
// Add field
woocommerce_form_field( 'my_id', array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __( '15% and some other text', 'woocommerce' ),
'required' => false,
), $checkout->get_value( 'my_id' ));
}
add_action( 'woocommerce_before_order_notes', 'action_woocommerce_before_order_notes', 10, 1 );

// Save checkbox value
function action_woocommerce_checkout_create_order( $order, $data ) {
// Set the correct value
$checkbox_value = isset( $_POST['my_id'] ) ? 'yes' : 'no';

// Update meta data
$order->update_meta_data( '_my_checkbox_value', $checkbox_value );
}
add_action( 'woocommerce_checkout_create_order', 'action_woocommerce_checkout_create_order', 10, 2 );

// Add table row on the checkout page
function action_woocommerce_before_order_total() {
// Initialize
$percent = 15;

// Get subtotal & shipping total
$subtotal = WC()->cart->subtotal;
$shipping_total = WC()->cart->get_shipping_total();

// Total
$total = $subtotal + $shipping_total;

// Result
$result = ( $total / 100 ) * $percent;

// The Output
echo '<tr class="my-class">
<th>' . __( 'My text', 'woocommerce' ) . '</th>
<td data-title="My text">' . wc_price( $result ) . '</td>
</tr>';
}
add_action( 'woocommerce_review_order_before_order_total', 'action_woocommerce_before_order_total', 10, 0 );

// Show/hide table row on the checkout page with jQuery
function action_wp_footer() {
// Only on checkout
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?>
<script type="text/javascript">
jQuery( function($){
// Selector
var my_input = 'input[name=my_id]';
var my_class = '.my-class';

// Show or hide
function show_or_hide() {
if ( $( my_input ).is(':checked') ) {
return $( my_class ).show();
} else {
return $( my_class ).hide();
}
}

// Default
$( document ).ajaxComplete(function() {
show_or_hide();
});

// On change
$( 'form.checkout' ).change(function() {
show_or_hide();
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer', 10, 0 );

// If desired, add new table row to emails, order received (thank you page) & my account -> view order
function filter_woocommerce_get_order_item_totals( $total_rows, $order, $tax_display ) {
// Get checkbox value
$checkbox_value = $order->get_meta( '_my_checkbox_value' );

// NOT equal to yes, return
if ( $checkbox_value != 'yes' ) return $total_rows;

// Initialize
$percent = 15;

// Get subtotal & shipping total
$subtotal = $order->get_subtotal();
$shipping_total = $order->get_shipping_total();

// Total
$total = $subtotal + $shipping_total;

// Result
$result = ( $total / 100 ) * $percent;

// Save the value to be reordered
$order_total = $total_rows['order_total'];

// Remove item to be reordered
unset( $total_rows['order_total'] );

// Add new row
$total_rows['my_text'] = array(
'label' => __( 'My text:', 'woocommerce' ),
'value' => wc_price( $result ),
);

// Reinsert removed in the right order
$total_rows['order_total'] = $order_total;

return $total_rows;
}
add_filter( 'woocommerce_get_order_item_totals', 'filter_woocommerce_get_order_item_totals', 10, 3 );

Checkout input text field that set a discount in WooCommerce

To enable a checkout input text field that set a custom discount in WooCommerce, few changes are required as follows:

// Display an input text field after billing fields
add_action( 'woocommerce_after_checkout_billing_form', 'add_custom_checkout_text_field', 20 );
function add_custom_checkout_text_field(){

woocommerce_form_field( 'custom_discount', array(
'type' => 'text',
'label' => __('Add a discount amount'),
'class' => array( 'form-row-wide' ),
), WC()->session->get('custom_discount') );
}

// Remove "(optional)" label on checkbox field
add_filter( 'woocommerce_form_field' , 'remove_order_comments_optional_fields_label', 10, 4 );
function remove_order_comments_optional_fields_label( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'custom_discount' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}

// Ajax / jQuery script
add_action( 'wp_footer', 'custom_discount_script' );
function custom_discount_script() {
// On checkoutpage
if( ( is_checkout() && ! is_wc_endpoint_url() ) ) :
?>
<script type="text/javascript">
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;

$(document.body).on('input change', 'input[name=custom_discount]', function(){
$.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: {
'action': 'custom_discount',
'custom_discount': $(this).val(),
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result);
},
});
});
});
</script>
<?php
endif;
}

// Get the ajax request and set value to WC session
add_action( 'wp_ajax_custom_discount', 'get_ajax_custom_discount' );
add_action( 'wp_ajax_nopriv_custom_discount', 'get_ajax_custom_discount' );
function get_ajax_custom_discount() {
if ( isset($_POST['custom_discount']) ) {
$discount = $_POST['custom_discount'] ? floatval($_POST['custom_discount']) : '';
WC()->session->set('custom_discount', $discount );
// echo WC()->session->get('custom_discount');
}
die();
}

// Add / Remove a custom discount
add_action( 'woocommerce_cart_calculate_fees', 'add_remove_custom_discount', 10, 1 );
function add_remove_custom_discount( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || is_cart() )
return;

$discount = (float) WC()->session->get('custom_discount');

if( $discount > 0 ) {
$cart->add_fee( __( 'Custom Discount', 'woocommerce'), -$discount );
}
}

// Reset WC Session custom discount variable
add_action( 'woocommerce_checkout_order_created', 'reset_wc_session_custom_discount_variable' );
function reset_wc_session_custom_discount_variable( $order ) {
if ( WC()->session->__isset('custom_discount') ) {
WC()->session->__unset('custom_discount');
}
}

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

Add Custom discount in WooCommerce Checkout based on a switch toggle

I have revisited your code a bit as there was some missing things:

  • The name attribute was missing from checkbox input field,
  • The Ajax action name was wrong on the composite hook from the Ajax receiver part.

Use the following:

// Display the field
add_action( 'woocommerce_review_order_before_payment', 'switch_toggle_fee_on_checkout', 20 );
function switch_toggle_fee_on_checkout() {

echo '<div class="switch-toggle-wrapper">
<span>' . __("To add the company discount, toggle this switch.", "woocommerce") . ' </span>
<label class="switch">
<input type="checkbox" name="company_discount" id="company_discount">
<span class="slider round"></span>
</label>
</div>';
}

// jQuery Ajax sender function
add_action( 'wp_footer', 'checkout_toggle_discount_script' );
function checkout_toggle_discount_script() {
if( is_checkout() && ! is_wc_endpoint_url() ) :

if( WC()->session->__isset('enable_discount') ) {
WC()->session->__unset('enable_discount');
}
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;

$('form.checkout').on('change', 'input[name="company_discount"]', function(){
console.log('toggle');
var toggle = $(this).prop('checked') === true ? '1' : '0';
$.ajax( {
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'enable_discount',
'discount_toggle': toggle,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}

// Ajax receiver: Set a WC_Session variable
add_action( 'wp_ajax_enable_discount', 'checkout_enable_discount_ajax' );
add_action( 'wp_ajax_nopriv_enable_discount', 'checkout_enable_discount_ajax' );
function checkout_enable_discount_ajax() {
if ( isset($_POST['discount_toggle']) ) {
WC()->session->set('enable_discount', esc_attr($_POST['discount_toggle']) ? true : false );
echo esc_attr($_POST['discount_toggle']);
}
wp_die();
}

// Set the discount
add_action( 'woocommerce_cart_calculate_fees', 'checkout_set_discount', 20, 1 );
function checkout_set_discount( $cart ) {
if ( ( is_admin() && ! defined('DOING_AJAX') ) || ! is_checkout() )
return;

$subtotal = WC()->cart->get_subtotal();
$percentage = 5;
$discount = $subtotal * $percentage / 100;

// Give 5% discount if and when the switch is toggled
if( WC()->session->get('enable_discount') ) {
$cart->add_fee( sprintf( __( 'Company Discount (%s)', 'woocommerce'), $percentage .'%' ), -$discount );
}
}

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

Add a percentage Fee with a fixed Fee to Woocommerce

Your code is a bit outdated, try the following instead that will add a fixed fee to the percentage fee:

add_action( 'woocommerce_cart_calculate_fees', 'woocommerce_custom_surcharge' );
function woocommerce_custom_surcharge( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;

$percentage = 0.03;
$fixed_fee = 0.3;

$percentage_fee = ( $cart->cart_contents_total + $cart->shipping_total ) * $percentage;
$surcharge = $fixed_fee + $percentage_fee;

$cart->add_fee( 'Processing Fee', $surcharge, true );
}

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

When using this hook outdated $global $woocommerce; is not needed as the hooked function can use the WC_Cart object variable as an argument…

Display/hide checkbox at WooCommerce checkout based on product ID in cart

Before you actually show the checkbox field, you will first have to go through the cart to see if the productID is NOT present.

Same for the validation, as it is a required field and would otherwise still be a required field, even though it is not present.

So you get:

// Function to check if a certain product ID is in cart
function is_product_in_cart() {
// Check if product in cart
// Multiple product IDs can be entered, separated by a comma
$targeted_ids = array( 32, 1234, 5678 );

// Flag no product in cart
$flag = false;

// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Check cart item for defined product Ids
if ( in_array( $cart_item['product_id'], $targeted_ids ) ) {
// Product is in cart
$flag = true;

// Break loop
break;
}
}
}

return $flag;
}

// Add field
function action_woocommerce_review_order_before_submit() {
// NOT true
if ( ! is_product_in_cart() ) {
// Add checkbox
woocommerce_form_field( 'privacy_policy', array(
'type' => 'checkbox',
'class' => array( 'form-row privacy' ),
'label_class' => array( 'woocommerce-form__label woocommerce-form__label-for-checkbox checkbox' ),
'input_class' => array( 'woocommerce-form__input woocommerce-form__input-checkbox input-checkbox' ),
'required' => true,
'label' => 'I\'ve read and accept the <a href="/privacy-policy">Privacy Policy</a>',
));
}
}
add_action( 'woocommerce_review_order_before_submit', 'action_woocommerce_review_order_before_submit', 9 );

// Validate
function action_woocommerce_checkout_process() {
// NOT true
if ( ! is_product_in_cart() ) {
// NOT isset
if ( ! isset( $_POST['privacy_policy'] ) ) {
wc_add_notice( __( 'Please acknowledge the Privacy Policy', 'woocommerce' ), 'error' );
}
}
}
add_action( 'woocommerce_checkout_process', 'action_woocommerce_checkout_process', 10, 0 );

// Save field
function action_woocommerce_checkout_create_order( $order, $data ) {
// Isset
if ( isset( $_POST['privacy_policy'] ) ) {
$order->update_meta_data( 'privacy_policy', sanitize_text_field( $_POST['privacy_policy'] ) );
}
}
add_action( 'woocommerce_checkout_create_order', 'action_woocommerce_checkout_create_order', 10, 2 );


Related Topics



Leave a reply



Submit