Woocommerce Custom Checkout Field to Add Fee to Order Ajax

How to enable more than one fee with ajax in Woocommerce checkout?

You forgot to register the second fee ajax action.
It should be like that.

add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );

add_action( 'wp_ajax_enable_fee_2', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee_2', 'get_enable_fee' );

add fee not work in payment price in woocommerce checkout

Finally i solved the problem.
When we click in place order button, new ajax request sends with another posted data (custom data send directly as post data not post_data param).
And i set a condition to it and solved:

add_action( 'woocommerce_cart_calculate_fees', 'prefix_add_discount_line' );
function prefix_add_discount_line( $cart )
{
if(isset($_POST['post_data']))
{
parse_str($_POST['post_data'], $posted_data);
if( isset($posted_data['isWallet']) )
{
WC()->cart->add_fee( 'wallet', -$posted_data['walletUsed'] );
}
}

if(isset($_POST['isWallet']))
{
WC()->cart->add_fee( 'wallet', -$_POST['walletUsed'] );
}
}

Add a fee for specific user roles when Ship to a different address? has been checked on WooCommerce checkout

Your code contains some mistakes, missing pieces, and unnecessary steps.

This answer shows (without any user restrictions) how to add a fee when "Ship to a different address?" has been checked:

// The jQuery Ajax request
function action_wp_footer() {
// Only checkout page
if ( is_checkout() && ! is_wc_endpoint_url() ) :

// Remove "ship_different" custom WC session on load
if ( WC()->session->get( 'ship_different' ) ) {
WC()->session->__unset( 'ship_different' );
}

// jQuery Ajax code below
?>
<script type="text/javascript">
jQuery( function($) {
if ( typeof wc_checkout_params === 'undefined' )
return false;

var a = '#ship-to-different-address-checkbox', b = '';

// Ajax function
function triggerSTDA( value ) {
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'ship_different_address',
'ship_different': value,
},
success: function (result) {
$( 'body' ).trigger( 'update_checkout' );
// console.log( result ); // For testing (to be removed)
}
});
}

$( a ).on( 'change', function() {
b = $( this ).prop('checked') === true ? 'yes' : 'no';
triggerSTDA( b );
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer' );

// The Wordpress Ajax PHP receiver
function get_ajax_ship_different_address() {
if ( isset( $_POST['ship_different'] ) ) {
WC()->session->set( 'ship_different', esc_attr( $_POST['ship_different'] ) );
echo $_POST['ship_different'];
}

die();
}
add_action( 'wp_ajax_ship_different_address', 'get_ajax_ship_different_address' );
add_action( 'wp_ajax_nopriv_ship_different_address', 'get_ajax_ship_different_address' );

// Add / remove a custom fee
function action_woocommerce_cart_calculate_fees( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || is_cart() )
return;

$fee_amount = 5;

if ( WC()->session->get( 'ship_different' ) == 'yes' ) {
$cart->add_fee( __( 'Shipping fee', 'woocommerce'), $fee_amount );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );

However, your question was to only apply this based on certain user roles:

So you get:

// The jQuery Ajax request
function action_wp_footer() {
// Only for logged in users
if ( ! is_user_logged_in() )
return;

// Only checkout page
if ( is_checkout() && ! is_wc_endpoint_url() ) :

// Remove "ship_different" custom WC session on load
if ( WC()->session->get( 'ship_different' ) ) {
WC()->session->__unset( 'ship_different' );
}

// jQuery Ajax code below
?>
<script type="text/javascript">
jQuery( function($) {
if ( typeof wc_checkout_params === 'undefined' )
return false;

var a = '#ship-to-different-address-checkbox', b = '';

// Ajax function
function triggerSTDA( value ) {
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'ship_different_address',
'ship_different': value,
},
success: function (result) {
$( 'body' ).trigger( 'update_checkout' );
// console.log( result ); // For testing (to be removed)
}
});
}

$( a ).on( 'change', function() {
b = $( this ).prop('checked') === true ? 'yes' : 'no';
triggerSTDA( b );
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer' );

// The Wordpress Ajax PHP receiver
function get_ajax_ship_different_address() {
if ( isset( $_POST['ship_different'] ) ) {
WC()->session->set( 'ship_different', esc_attr( $_POST['ship_different'] ) );
echo $_POST['ship_different'];
}

die();
}
add_action( 'wp_ajax_ship_different_address', 'get_ajax_ship_different_address' );
add_action( 'wp_ajax_nopriv_ship_different_address', 'get_ajax_ship_different_address' );

// Add / remove a custom fee
function action_woocommerce_cart_calculate_fees( $cart ) {
// Only on checkout
if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || is_cart() )
return;

// Only for logged in users
if ( ! is_user_logged_in() )
return;

// Get current WP_User Object
$user = wp_get_current_user();

// Roles to check, adapt to your specific needes
$roles_to_check = array( 'team', 'team2', 'administrator' );

// User roles
$roles = ( array ) $user->roles;

// Compare
$compare = array_diff( $roles, $roles_to_check );

// Result is empty
if ( empty ( $compare ) ) {
// Amount
$fee_amount = 5;

if ( WC()->session->get( 'ship_different' ) == 'yes' ) {
$cart->add_fee( __( 'Shipping fee', 'woocommerce'), $fee_amount );
}
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );

Partly used in this answer

  • Show hide payment gateways based on checkout fields in Woocommerce
  • Checkbox field that add / remove a custom fee in WooCommerce
  • Check WooCommerce User Role and Payment Gateway and if they match - Apply fee

Add or remove a fixed Fee based on a checkbox in WooCommerce checkout

You need to simply to make some little changes in your code like:

add_action('woocommerce_after_checkout_billing_form', 'checkout_shipping_form_packing_addition', 20);
function checkout_shipping_form_packing_addition()
{
$domain = 'woocommerce';

echo '<tr class="packing-select"><th>' . __('EMBRULHO?', $domain) . '</th><td>';

$chosen = WC()->session->get('chosen_packing');

// Add a custom checkbox field
woocommerce_form_field('chosen_packing', array(
'type' => 'checkbox',
'class' => array('form-row-wide packing'),
'label' => __('$5', 'woocommerce'),
'required' => false,
), $chosen);

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

// jQuery - Ajax script
add_action('wp_footer', 'checkout_shipping_packing_script');
function checkout_shipping_packing_script()
{
// Only checkout page
if (is_checkout() && !is_wc_endpoint_url()) :
?>
<script type="text/javascript">
jQuery(function($) {
$('form.checkout').on('change', 'input#chosen_packing', function() {
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'woo_get_ajax_data',
'packing': $(this).prop('checked') ? 1 : 0,
},
success: function(result) {
$('body').trigger('update_checkout');
console.log('response: ' + result); // just for testing | TO BE REMOVED
},
error: function(error) {
console.log(error); // just for testing | TO BE REMOVED
}
});
});
});
</script>
<?php
else:
WC()->session->__unset('chosen_packing');
endif;
}

// Php Ajax (Receiving request and saving to WC session)
add_action('wp_ajax_woo_get_ajax_data', 'woo_get_ajax_data');
add_action('wp_ajax_nopriv_woo_get_ajax_data', 'woo_get_ajax_data');
function woo_get_ajax_data()
{
if (isset($_POST['packing'])) {
$packing = sanitize_key($_POST['packing']);
WC()->session->set('chosen_packing', $packing);
echo json_encode($packing);
}
die(); // Alway at the end (to avoid server error 500)
}

// Add a custom dynamic packaging fee
add_action('woocommerce_cart_calculate_fees', 'add_packaging_fee', 20, 1);
function add_packaging_fee($cart)
{
if (is_admin() && !defined('DOING_AJAX'))
return;

if( WC()->session->get('chosen_packing') ){
$label = __('Embrulho', 'woocommerce');
$cost = 5;
$cart->add_fee($label, $cost);
}
}

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

WooCommerce - Add fee based on custom field

The reason why you unable to get value from $_POST['add_gift_message'] is because update_checkout is an ajax event and it serialise form data into $_POST['post_data']. So, in order to cater for getting the value before (ajax) and during(non-ajax) user check out, you can get that by using below code:

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_message'] ) ) {

$woocommerce->cart->add_fee( 'Personal Gift Message', '4.00', true, 'standard' );
}

for reference, can see this post

Custom checkbox that adds a fee in WooCommerce cart page

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.

Custom checkout field and shipping methods ajax interaction in Woocommerce 3

Try the following revisited code is based on your provided code that will add in a custom WC_Session the value of the Billing Area field through Ajax.

Then you will be able to get the live value using: $value = WC()->session->get('billing_area'); in a custom function hooked in woocommerce_shipping_packages filter hook located in WC_Shipping method calculate_shipping() as you asked.

The code:

// Add a custom billing field
add_filter( 'woocommerce_billing_fields', 'add_custom_billing_field', 20, 1 );
function add_custom_billing_field($billing_fields) {

$billing_fields['billing_area'] = array(
'label' => __('Area', 'woocommerce'),
'placeholder' => _x('Fill in your area', 'placeholder', 'woocommerce'),
'required' => true,
'class' => array('form-row-wide' ),
'clear' => true,
'priority' => 65
);
return $billing_fields;
}

// The Wordpress Ajax PHP receiver
add_action( 'wp_ajax_billing_area', 'get_ajax_billing_area' );
add_action( 'wp_ajax_nopriv_billing_area', 'get_ajax_billing_area' );
function get_ajax_billing_area() {
if ( isset($_POST['billing_area']) ){
WC()->session->set('billing_area', esc_attr($_POST['billing_area']));
echo $_POST['billing_area'];
}
die();
}

// Refreshing session shipping methods data (Mandatory)
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( WC()->session->get('billing_area' ) != '' ) $bool = false;

// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}

// The jQuery Ajax request
add_action( 'wp_footer', 'checkout_billing_area_script' );
function checkout_billing_area_script() {
// Only checkout page
if( is_checkout() && ! is_wc_endpoint_url() ):

// Remove "billing_area" custom WC session on load
if( WC()->session->get('billing_area') ){
WC()->session->__unset('billing_area');
}
// jQuery Ajax code below
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;

var a = '#billing_area', f = 'form.checkout';

// Ajax function
function checkBArea( value ){
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'billing_area',
'billing_area': value,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result); // For testing (to be removed)
}
});
}

// On start
if( $(a).val() != '' )
checkBArea($(a).val());

// On change event
$(f).on('change', a, function() {
checkBArea($(this).val());
});
});
</script>
<?php
endif;
}

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


Similar or related threads:

  • Disable shipping method based on chosen payment method in Woocommerce
  • Remove shipping cost if custom checkbox is checked in WooCommerce Checkout


Related Topics



Leave a reply



Submit