Based on Display a checkbox that add a fee in Woocommerce checkout page answer code I am trying to change usage to Cart page, rather than checkout page per clients request.
So far I managed to display custom fee check box on cart page and trigger Ajax.
However Cart totals are not updated.
If someone can help on code or point me in right direction?
// Display the custom checkbox field in cart
add_action( 'woocommerce_cart_totals_before_order_total', 'fee_installment_checkbox_field', 20 );
function fee_installment_checkbox_field(){
echo '<tr class="packing-select"><th>Priority Dispatch</th><td>';
woocommerce_form_field( 'priority_fee', array(
'type' => 'checkbox',
'class' => array('installment-fee form-row-wide'),
'label' => __(' $20.00'),
'placeholder' => __(''),
), WC()->session->get('priority_fee') ? '1' : '' );
echo '<div class="tooltip">?
<span class="tooltiptext">By selecting this option... </span>
</div></td>';
}
// jQuery - Ajax script
add_action( 'wp_footer', 'woo_add_cart_fee' );
function woo_add_cart_fee() {
// Only on Checkout
if( ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('priority_fee') )
WC()->session->__unset('priority_fee')
?>
<script type="text/javascript">
jQuery( function($){
//if (typeof wc_add_to_cart_params === 'undefined')
// return false;
$('tr.packing-select').on('change', 'input[name=priority_fee]', function(){
console.log('tests');
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
//url: wc_add_to_cart_params.ajax_url,
data: {
'action': 'priority_fee',
'priority_fee': fee,
},
success: function (response) {
$('body').trigger('added_to_cart');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_priority_fee', 'get_priority_fee' );
add_action( 'wp_ajax_nopriv_priority_fee', 'get_priority_fee' );
function get_priority_fee() {
if ( isset($_POST['priority_fee']) ) {
WC()->session->set('priority_fee', ($_POST['priority_fee'] ? true : false) );
}
die();
}
// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_priority_fee' );
function set_priority_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') )
return;
if ( did_action('woocommerce_cart_calculate_fees') >= 2 )
return;
if ( 1 == WC()->session->get('priority_fee') ) {
$items_count = WC()->cart->get_cart_contents_count();
$fee_label = sprintf( __( "PRIORITY DISPATCH %s %s" ), '×', $items_count );
$fee_amount = 20;
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( 'priority_fee' === $key ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
Additionally is this the way this should be done, or is there an easier way to do it?
There are some mistakes in your code. Also, on cart page, jQuery events and Ajax behavior are a bit different, so it requires some changes:
// Display the checkout field in cart page totals section
add_action( 'woocommerce_cart_totals_before_order_total', 'display_priority_fee_checkbox_field', 20 );
function display_priority_fee_checkbox_field(){
echo '<tr class="installment-section">
<th>'.__("Priority Dispatch").'</th><td>';
woocommerce_form_field( 'priority_fee', array(
'type' => 'checkbox',
'class' => array('form-row-wide'),
'label' => __(' $20.00'),
), WC()->session->get('priority_fee') ? '1' : '' );
echo '<div class="tooltip">?
<span class="tooltiptext">'.__("By selecting this option... ").'</span>
</div></td>';
}
// Remove "(optional)" text from the field
add_filter( 'woocommerce_form_field' , 'remove_optional_txt_from_priority_fee_checkbox', 10, 4 );
function remove_optional_txt_from_priority_fee_checkbox( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'priority_fee' === $key ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery :: Ajax script
add_action( 'wp_footer', 'priority_fee_js_script' );
function priority_fee_js_script() {
// On Order received page, remove the wc session variable if it exist
if ( is_wc_endpoint_url('order-received')
&& WC()->session->__isset('priority_fee') ) :
WC()->session->__unset('priority_fee');
// On Cart page: jQuert script
elseif ( is_cart() ) :
?>
<script type="text/javascript">
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;
var c = 'input[name=priority_fee]';
$(document.body).on( 'click change', c, function(){
console.log('click');
var fee = $(c).is(':checked') ? '1' : '';
$.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: {
'action': 'priority_fee',
'priority_fee': fee,
},
success: function (response) {
setTimeout(function(){
$(document.body).trigger('added_to_cart');
}, 500);
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_priority_fee', 'priority_fee_ajax_receiver' );
add_action( 'wp_ajax_nopriv_priority_fee', 'priority_fee_ajax_receiver' );
function priority_fee_ajax_receiver() {
if ( isset($_POST['priority_fee']) ) {
$priority_fee = $_POST['priority_fee'] ? true : false;
// Set to a WC Session variable
WC()->session->set('priority_fee', $priority_fee );
echo $priority_fee ? '1' : '0';
die();
}
}
// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_priority_fee' );
function set_priority_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') )
return;
if ( WC()->session->get('priority_fee') ) {
$item_count = $cart->get_cart_contents_count();
$fee_label = sprintf( __( "PRIORITY DISPATCH %s" ), '× ' . $item_count );
$fee_amount = 20 * $item_count;
$cart->add_fee( $fee_label, $fee_amount );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Related
In Woocommerce checkout page, I'am trying to add a check box on checkout page
I have referred to these articles
woocommerce custom checkout field to add fee to order ajax
Checkbox field that add / remove a custom fee in WooCommerce
Add a checkout checkbox field that enable a percentage fee in Woocommerce
add_action( 'woocommerce_review_order_before_order_total', 'checkout_shipping_form_packing_addition', 20 );
function checkout_shipping_form_packing_addition( ){
echo '<tr class="packing-select"><th>';
woocommerce_form_field( 'add_gift_box', array(
'type' => 'checkbox',
'class' => array('add_gift_box form-row-wide'),
'label' => __('Hỗ trợ cài đặt'),
'placeholder' => __(''),
));
echo '</th><td>';}
add_action( 'wp_footer', 'woocommerce_add_gift_box' );
function woocommerce_add_gift_box() {
if (is_checkout()) {
?>
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
$('#add_gift_box').click(function(){
jQuery('body').trigger('update_checkout');
});
});
</script>
<?php
}}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
function woo_add_cart_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; // fallback for final checkout (non-ajax)
}
if (isset($post_data['add_gift_box'])) {
$sl = WC()->cart->get_cart_contents_count();
$extracost = 50000 * $sl; // not sure why you used intval($_POST['state']) ?
WC()->cart->add_fee( 'Hỗ trợ cài đặt x '.$sl.'', $extracost );
}}
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( 'add_gift_box' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
It does not work as I would like. What I am doing wrong?
Any help is appreciated.
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.
I am trying to modify the code based on this question:
// Display the checkout field in cart page totals section
add_action( 'woocommerce_cart_totals_before_order_total', 'display_priority_fee_checkbox_field', 20 );
function display_priority_fee_checkbox_field(){
echo '<tr class="installment-section">
<th>'.__("Priority Dispatch").'</th><td>';
woocommerce_form_field( 'priority_fee', array(
'type' => 'checkbox',
'class' => array('form-row-wide'),
'label' => __(' $20.00'),
), WC()->session->get('priority_fee') ? '1' : '' );
echo '<div class="tooltip">?
<span class="tooltiptext">'.__("By selecting this option... ").'</span>
</div></td>';
}
// Remove "(optional)" text from the field
add_filter( 'woocommerce_form_field' , 'remove_optional_txt_from_priority_fee_checkbox', 10, 4 );
function remove_optional_txt_from_priority_fee_checkbox( $field, $key, $args, $value ) {
// Only on checkout page for Order notes field
if( 'priority_fee' === $key ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
// jQuery :: Ajax script
add_action( 'wp_footer', 'priority_fee_js_script' );
function priority_fee_js_script() {
// On Order received page, remove the wc session variable if it exist
if ( is_wc_endpoint_url('order-received')
&& WC()->session->__isset('priority_fee') ) :
WC()->session->__unset('priority_fee');
// On Cart page: jQuert script
elseif ( is_cart() ) :
?>
<script type="text/javascript">
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;
var c = 'input[name=priority_fee]';
$(document.body).on( 'click change', c, function(){
console.log('click');
var fee = $(c).is(':checked') ? '1' : '';
$.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: {
'action': 'priority_fee',
'priority_fee': fee,
},
success: function (response) {
setTimeout(function(){
$(document.body).trigger('added_to_cart');
}, 500);
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_priority_fee', 'priority_fee_ajax_receiver' );
add_action( 'wp_ajax_nopriv_priority_fee', 'priority_fee_ajax_receiver' );
function priority_fee_ajax_receiver() {
if ( isset($_POST['priority_fee']) ) {
$priority_fee = $_POST['priority_fee'] ? true : false;
// Set to a WC Session variable
WC()->session->set('priority_fee', $priority_fee );
echo $priority_fee ? '1' : '0';
die();
}
}
// Add a custom calculated fee conditionally
add_action( 'woocommerce_cart_calculate_fees', 'set_priority_fee' );
function set_priority_fee( $cart ){
if ( is_admin() && ! defined('DOING_AJAX') )
return;
if ( WC()->session->get('priority_fee') ) {
$item_count = $cart->get_cart_contents_count();
$fee_label = 'Discount';
$fee_amount = -2;
$cart->add_fee( $fee_label, $fee_amount );
}
}
But the discount is not showing up. Also, I nneed the discount to be applied to the SUBTOTALS so that tax is recalculated as well (which the code does not do, it applies the discount after taxes).
How can I set a negative fee(discount) when checkbox is checked and also have the discount applied before tax calculation?
EDIT: Okay, I got it to work with the taxes by changing the last part:
// 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') ) )
return;
$subtotal = WC()->cart->get_subtotal();
$percentage = 1;
$discount = $subtotal * $percentage / 100;
if( WC()->session->get('priority_fee') ) {
$cart->add_fee( sprintf( __( 'Discount', 'woocommerce') ), -$discount );
}
}
but this only works with a percentage based discount. How can I instead use a fixed discount?
Based on Add a checkout checkbox field that enable a percentage fee in Woocommerce answer code I created a checkbox on the checkout page.
When it is checked, it applies a 15% freight forwarding fee.
// Add a custom checkbox fields before order notes
add_action( 'woocommerce_before_order_notes', 'add_custom_checkout_checkbox', 20 );
function add_custom_checkout_checkbox(){
// Add a custom checkbox field
woocommerce_form_field( 'forwarding_fee', array(
'type' => 'checkbox',
'label' => __('15% forwarding fee'),
'class' => array( 'form-row-wide' ),
), '' );
}
// 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('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=forwarding_fee]', 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;
}
// 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_percetage_fee', 20, 1 );
function custom_percetage_fee( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
return;
$percent = 15;
if( WC()->session->get('enable_fee') )
$cart->add_fee( __( 'Forwarding fee', 'woocommerce')." ($percent%)", ($cart->get_subtotal() * $percent / 100) );
}
Currently, this fee is calculated from the subtotal and added up to the order total value.
I need a solution where this fee is calculated from a sum of subtotal + shipping AND IS NOT added to the order total value.
I will rename "fee" to "deposit".
Please see a screenshot:
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 );
I have created a checkbox (It does not look like a checkbox anymore) that apply/remove a coupong on change. This works good. But the total does not update on the apply, the page has to be refreshed. I have build this function with some cut and paste from other functions, it was once a radio field, and it might not be the best practise. The coupong ads a discount for 500 SEK.
But how to do I recalculate the total after the coupong is applied?
As you can see in the end, I have tried WC()->cart->calculate_totals();.
This is the site and checkout: https://www.klubbtryck.se/nif/kassa/
This is my code:
// Add a custom checkout field
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_form_delivery_addition_nifny', 20 );
function checkout_shipping_form_delivery_addition_nifny(){
$domain = 'wocommerce';
if ( WC()->session->get( 'chosen_shipping_methods' )[0] == 'local_pickup:3' ) :
echo '<tr class="delivery-radio"><th>' . __('Gift Card', $domain) . '</th><td>';
$chosen = WC()->session->get('chosen_delivery');
$chosen = empty($chosen) ? WC()->checkout->get_value('delivery') : $chosen;
$chosen = empty($chosen) ? 0 : $chosen;
if( $chosen == 1){ $chosen = true; } else { $chosen = false; }
// Add a custom checkbox field
woocommerce_form_field( 'radio_delivery', array(
'type' => 'checkbox',
'label' => '<label for="radio_delivery" class="checkbox-label"><span class="presentkortbesk">I have a gift card</span><span class="priset">-500kr</span></label>',
'class' => array( 'form-row-wide' ),
'required' => false,
//'default' => false,
), $chosen );
echo '</td></tr>';
endif;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_delivery_script_nifny' );
function checkout_delivery_script_nifny() {
// Only checkout page
if ( ! is_checkout() ) return;
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name=radio_delivery]', function(e){
e.preventDefault();
var d = $(this).prop('checked') === true ? 1 : 0;
//var d = $(this).val();
//alert('value: '+d);
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'delivery',
'delivery': d,
},
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', 'wc_get_delivery_ajax_data_nifny' );
add_action( 'wp_ajax_nopriv_delivery', 'wc_get_delivery_ajax_data_nifny' );
function wc_get_delivery_ajax_data_nifny() {
if ( isset($_POST['delivery']) ){
WC()->session->set('chosen_delivery', sanitize_key( $_POST['delivery'] ) );
echo json_encode( $delivery ); // Return the value to jQuery
}
die();
}
// Add a custom dynamic delivery fee
add_action( 'woocommerce_cart_calculate_fees', 'add_packaging_fee_nifny', 20, 1 );
function add_packaging_fee_nifny( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Only for targeted shipping method
if ( WC()->session->get( 'chosen_shipping_methods' )[0] != 'local_pickup:3' )
return;
if( WC()->session->get( 'chosen_delivery' ) == 1 ){
if (!in_array('nynashamn2020', WC()->cart->get_applied_coupons())) {
WC()->cart->apply_coupon('card2020');
//WC()->cart->calculate_totals();
}
} else {
if (in_array('nynashamn2020', WC()->cart->get_applied_coupons())) {
WC()->cart->remove_coupon('card2020');
}
}
}
You should replace woocommerce_cart_calculate_fees hook that is only made for Fees with similar woocommerce_before_calculate_totals more appropriated hook as follows:
// Add a custom dynamic delivery fee
add_action( 'woocommerce_before_calculate_totals', 'add_packaging_fee_nifny' );
function add_packaging_fee_nifny( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Only for targeted shipping method
if ( WC()->session->get( 'chosen_shipping_methods' )[0] != 'local_pickup:3' )
return;
if( WC()->session->get( 'chosen_delivery' ) == 1 ){
if (!in_array('nynashamn2020', WC()->cart->get_applied_coupons())) {
WC()->cart->apply_coupon('card2020');
//WC()->cart->calculate_totals();
}
} else {
if (in_array('nynashamn2020', WC()->cart->get_applied_coupons())) {
WC()->cart->remove_coupon('card2020');
}
}
}
Code goes in functions.php file of the active child theme (or active theme). It should better works.
In Woocommerce checkout page, I'am trying to add a check box on checkout page
I have referred to these articles
woocommerce custom checkout field to add fee to order ajax
Checkbox field that add / remove a custom fee in WooCommerce
Add a checkout checkbox field that enable a percentage fee in Woocommerce
add_action( 'woocommerce_review_order_before_order_total', 'checkout_shipping_form_packing_addition', 20 );
function checkout_shipping_form_packing_addition( ){
echo '<tr class="packing-select"><th>';
woocommerce_form_field( 'add_gift_box', array(
'type' => 'checkbox',
'class' => array('add_gift_box form-row-wide'),
'label' => __('Hỗ trợ cài đặt'),
'placeholder' => __(''),
));
echo '</th><td>';}
add_action( 'wp_footer', 'woocommerce_add_gift_box' );
function woocommerce_add_gift_box() {
if (is_checkout()) {
?>
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
$('#add_gift_box').click(function(){
jQuery('body').trigger('update_checkout');
});
});
</script>
<?php
}}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
function woo_add_cart_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; // fallback for final checkout (non-ajax)
}
if (isset($post_data['add_gift_box'])) {
$sl = WC()->cart->get_cart_contents_count();
$extracost = 50000 * $sl; // not sure why you used intval($_POST['state']) ?
WC()->cart->add_fee( 'Hỗ trợ cài đặt x '.$sl.'', $extracost );
}}
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( 'add_gift_box' === $key && is_checkout() ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}
It does not work as I would like. What I am doing wrong?
Any help is appreciated.
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.