Remove shipping cost if custom checkbox is checked in WooCommerce Checkout - php

I am trying to set the price of shipping rates to $0.00 if a checkbox in the checkout fields is checked.
Current Attempt:
function no_shipping_for_own_ups($rates,$package) {
foreach ($rates as $rate) {
//Set the price
$rate->cost = 0;
}
return $rates;
}
function woo_add_cart_ups_y_n_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;
}
if (isset($post_data['billing_ups_yn'])) {
add_filter( 'woocommerce_package_rates','no_shipping_for_own_ups', 99, 2 );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_ups_y_n_fee', 43, 1 );
As $post_data['billing_ups_yn'] being the checkbox that I set to update the checkout when triggered.
Simply if the checkbox is checked, then apply the filter to set shipping rates to 0.
This, however, isn't working.

To alter shipping methods cost via Ajax on a custom javascript event in checkout page is quiet more complicated than conditionally altering fees or anything else as you will see below.
To store the Ajax data I use WC_Sessions and to alter Shipping methods costs will only work if you manipulate the shipping sessions data
The full working code:
// Add a Custom checkbox field for shipping options (just for testing)
add_action( 'woocommerce_after_checkout_billing_form', 'custom_billing_checkbox_for_testing', 10, 1 );
function custom_billing_checkbox_for_testing( $checkout ) {
$field_id = 'billing_ups_yn';
// Get the checked state if exist
$billing_ups = WC()->session->get('billing_ups' );
if(empty($billing_ups))
$billing_ups = $checkout->get_value( $field_id );
// Add the custom checkout field (checkbox)
woocommerce_form_field( $field_id, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Billing UPS'),
), $billing_ups );
}
// function that gets the Ajax data
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 ( $_POST['billing_ups'] == '1' ){
WC()->session->set('billing_ups', '1' );
} else {
WC()->session->set('billing_ups', '0' );
}
echo json_encode( WC()->session->get('billing_ups' ) );
die(); // Alway at the end (to avoid server error 500)
}
// Conditionally changing the shipping methods costs
add_filter( 'woocommerce_package_rates','conditional_custom_shipping_cost', 90, 2 );
function conditional_custom_shipping_cost( $rates, $package ) {
if ( WC()->session->get('billing_ups' ) == '1' ){
foreach ( $rates as $rate_key => $rate_values ) {
// Not for "Free Shipping method" (all others only)
if ( 'free_shipping' !== $rate_values->method_id ) {
// Set the rate cost
$rates[$rate_key]->cost = 0;
// Set taxes rate cost (if enabled)
$taxes = array();
foreach ($rates[$rate_key]->taxes as $key => $tax)
if( $rates[$rate_key]->taxes[$key] > 0 ) // set the new tax cost
$taxes[$key] = 0;
$rates[$rate_key]->taxes = $taxes;
}
}
}
return $rates;
}
// Enabling, disabling and refreshing session shipping methods data
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_ups' ) == '1' ) $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 script
add_action( 'wp_footer', 'custom_checkout_script' );
function custom_checkout_script() {
?>
<script type="text/javascript">
jQuery( function($){
// update cart on delivery location checkbox option
$('#billing_ups_yn_field input').change( function () {
var checked = 0;
if ( $('#billing_ups_yn').is(':checked') )
checked = 1;
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'woo_get_ajax_data',
'billing_ups': checked,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log('response: '+result); // just for testing
},
error: function(error){
console.log(error); // just for testing
}
});
});
});
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works.
Update related to your comment:
If you wish to have always the checkbox unchecked by default at load you will replace the first function by this one:
// Add a Custom checkbox field for shipping options (just for testing)
add_action( 'woocommerce_after_checkout_billing_form', 'custom_billing_checkbox_for_testing', 10, 1 );
function custom_billing_checkbox_for_testing( $checkout ) {
$field_id = 'billing_ups_yn';
// Add the custom checkout field (checkbox)
woocommerce_form_field( $field_id, array(
'type' => 'checkbox',
'class' => array( 'form-row-wide' ),
'label' => __('Billing UPS'),
), '' );
}

I have similar project about 3 years ago and has radio button and date picker that will both modify and update the shipping details/amount when changed, the radio button will modify Shipping surcharge and the date picker will have -10 discount price when Saturday and Friday is selected from the calendar.
working example here
I assume you had knowledge with PHP and AJax and can modify this, you only need to modify few things like the session value and calculation as well as those jquery selector and form fields selector
function to handle ajax request, the purpose is to only assign $_SESSION value
add_action('wp_ajax_woo_modify_charges', 'etq_calculate', 10);
add_action('wp_ajax_nopriv_woo_modify_charges', 'etq_calculate', 10);
function etq_calculate() {
global $woocommerce;
$charge = isset($_POST['billing_area']) ? $_POST['billing_area'] : 'no';
$deldate = isset($_POST['jck_delivery_date']) ? $_POST['jck_delivery_date'] : '06/08/2015';
$delday = strtotime(str_replace('/', '-', $deldate));
$day = date('l', $delday);
if ( $day === 'Saturday' || $day === 'Friday') $val = -10;
else $val = 0;
if ( $charge === 'no' ) $surchage = 0;
else $surchage = 10;
if( !isset($_SESSION) ) session_start();
$_SESSION['val'] = $val;
$_SESSION['surcharge'] = $surchage;
}
Next function is to hook the modification on woocommerce_cart_calculate_fees from the value of $_SESSION.. this is where the price update happens
add_action('woocommerce_cart_calculate_fees', 'woo_change_cart_fee');
function woo_change_cart_fee() {
if(!isset($_SESSION)) session_start();
$surcharge = isset($_SESSION['surcharge']) ? $_SESSION['surcharge'] : 0;
$discount = isset($_SESSION['val']) ? $_SESSION['val'] : 0;
if ( $surcharge !== '0' ) WC()->cart->add_fee('Shipping Surchage', $surcharge, false, '');
if ( $discount !== '0' ) WC()->cart->add_fee('Delivery Discount', $discount, false, '');
}
then for jquery script that handles ajax
(function($){
'use strict';
$(document).ready( function() {
var $date_field = $('#jck_delivery_date');
// update cart on delivery date changes
$('#jck_delivery_date').bind('change', function () {
if ($('#billing_area_yes').is(':checked')) {
var surcharge = $('#billing_area_yes').val();
$('#billing_area_yes').prop('checked', true);
} else {
var surcharge = 'no';
}
var deldate = $('#jck_delivery_date').val();
var data = {
action: 'woo_modify_charges',
jck_delivery_date: deldate,
billing_area: surcharge
};
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: data,
success: function (code) {
console.log(code);
//jQuery('.woocommerce-error, .woocommerce-message').remove();
if (code === '0') {
//$form.before(code);
$('body').trigger('update_checkout');
}
},
dataType: 'html'
});
return false;
});
// update cart on delivery location checkbox option
$('#billing_area_field input').change( function () {
if ($('#billing_area_yes').is(':checked')) {
var surcharge = $('#billing_area_yes').val();
} else {
var surcharge = 'no';
}
var deldate = $('#jck_delivery_date').val();
console.log( surcharge );
var data = {
action: 'woo_modify_charges',
billing_area: surcharge,
jck_delivery_date: deldate,
};
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: data,
success: function (code) {
console.log(code);
//jQuery('.woocommerce-error, .woocommerce-message').remove();
if (code === '0') {
//$form.before(code);
$('body').trigger('update_checkout');
}
},
dataType: 'html'
});
return false;
});
});
})(jQuery);

Related

Show additional information depending on shipping selected

I would like to show additional information/order notes when a specific shipping method was selected.
I have multiple shipping options and when selecting a specific one I need the user to provide a different address in the note, please see the images below:
These are the available shipping options:
I want to show this (and it has to be a required field)
I have seen this answer where a checkbox is used to show/hide the notes of an order on the checkout page:
By doing the following:
add_filter( 'woocommerce_checkout_fields', 'custom_checkout_order_notes' );
function custom_checkout_order_notes( $fields ) {
$fields['order']['order_comments']['class'][] = 'off';
return $fields;
}
add_action( 'woocommerce_before_order_notes', 'checkout_checkbox_show_hide_order_notes' );
function checkout_checkbox_show_hide_order_notes( $fields ) {
$target_id = 'order_comments';
?>
<style> p#<?php echo $target_id; ?>_field.off { display:none;}</style>
<script type="text/javascript">
jQuery(function($){
var a = 'input#checkbox_trigger', b = '#<?php echo $target_id; ?>_field';
$(b).hide('fast');
$(a).change(function(){
if( $(b).hasClass('off') ) {
$(b).removeClass('off');
}
if ( $(this).prop('checked') ) {
$(b).show('fast');
} else {
$(b).hide('fast', function(){
$(b+' input').val('');
});
}
});
});
</script>
<?php
woocommerce_form_field( 'checkbox_trigger', array(
'type' => 'checkbox',
'label' => __('Add a note to your order?', 'woocommerce'),
'class' => array('form-row-wide'),
'clear' => true,
), false );
}
But this is not what I want as described above.
Any help would greatly be appreciated.
I figured it out. I have added comments to help future readers.
add_action( 'woocommerce_billing_fields','woocommerce_check_if_shipping_changed' );
function woocommerce_check_if_shipping_changed() {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Get the selected shipping method
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
// Check if it is one of the two I want to show "Aditional Information" for (using their ID's)
// I used developer tools to get their ID's
if ($chosen_shipping == 'wbs:6:5977f58e_postnet_to_postnet' || $chosen_shipping == 'wbs:6:014e3dff_pudo_locker') {
if ($chosen_shipping == 'wbs:6:014e3dff_pudo_locker'){
// Change additional notes label to : Pudo Locker Address:
add_filter('woocommerce_checkout_fields', 'make_order_label_pudo', 9999, 1);
}
if ($chosen_shipping == 'wbs:6:5977f58e_postnet_to_postnet'){
// Change additional notes label to : PostNet Address:
add_filter('woocommerce_checkout_fields', 'make_order_label_postnet', 9999, 1);
}
// Show order notes
add_filter( 'woocommerce_enable_order_notes_field', '__return_true', 9999 );
// Make order notes required
add_filter('woocommerce_checkout_fields', 'make_order_notes_required_field', 9999, 1);
}else{
// Hide order notes
add_filter( 'woocommerce_enable_order_notes_field', '__return_false', 9999 );
// Make order notes not a requirement
add_filter('woocommerce_checkout_fields', 'make_order_notes_not_required_field', 9999, 1);
}
}
function make_order_label_pudo( $fields ) {
$fields['order']['order_comments']['label'] = 'Pudo Locker Address:';
return $fields;
}
function make_order_label_postnet( $fields ) {
$fields['order']['order_comments']['label'] = 'PostNet Address:';
return $fields;
}
function make_order_notes_required_field( $fields ) {
$fields['order']['order_comments']['required'] = true;
return $fields;
}
function make_order_notes_not_required_field( $fields ) {
$fields['order']['order_comments']['required'] = false;
return $fields;
}
// The page needs to be refreshed of the changes to apply
add_action( 'wp_footer', 'checkout_shipping_refresh' );
function checkout_shipping_refresh() {
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?><script type="text/javascript">
jQuery( function($){
let isRefreshPage = false;
$('form.checkout').on('change','input[name^="shipping_method"]',function() {
const val = $( this ).val();
isRefreshPage = true;
});
$('body').on('updated_checkout', function(){
if (isRefreshPage) {
location.reload();
}
});
});
</script>
<?php
endif;
}

Ajax Add to cart for simple and variable products on WooCommerce single products

The code below is working for add to cart with WooCommerce for simple products, but not for variable products. Can someone help me out? Because this code works with the latest WC, please do not remove this question because there are lots of codes for this online that do not work at all.
The error I am getting that is says in a notice that I should choose a product option, even when I chose one.
JS:
jQuery(function($) {
$('form.cart').on('submit', function(e) {
e.preventDefault();
var form = $(this);
form.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } });
var formData = new FormData(form.context);
formData.append('add-to-cart', form.find('[name=add-to-cart]').val() );
var $thisbutton = form.find('.single_add_to_cart_button'); //
// Ajax action
$.ajax({
url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'ace_add_to_cart' ),
data: formData,
type: 'POST',
processData: false,
contentType: false,
beforeSend: function (response) {
$thisbutton.removeClass('added').addClass('loading');
},
complete: function( response ) {
response = response.responseJSON;
if ( ! response ) {
return;
}
if ( response.error && response.product_url ) {
window.location = response.product_url;
return;
}
// Redirect to cart option
if ( wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
window.location = wc_add_to_cart_params.cart_url;
return;
}
// Trigger event so themes can refresh other areas.
$( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $thisbutton ] );
// Remove existing notices
$( '.woocommerce-error, .woocommerce-message, .woocommerce-info' ).remove();
// Add new notices
form.closest('.product').before(response.fragments.notices_html)
form.unblock();
}
});
});
});
PHP:
/* WOOCOMMERCE AJAX ADD TO CART
--------------------------------------------------- */
function ace_ajax_add_to_cart_handler() {
WC_Form_Handler::add_to_cart_action();
WC_AJAX::get_refreshed_fragments();
}
/* Add fragments for notices. */
function ace_ajax_add_to_cart_add_fragments( $fragments ) {
$all_notices = WC()->session->get( 'wc_notices', array() );
$notice_types = apply_filters( 'woocommerce_notice_types', array( 'error', 'success', 'notice' ) );
ob_start();
foreach ( $notice_types as $notice_type ) {
if ( wc_notice_count( $notice_type ) > 0 ) {
wc_get_template( "notices/{$notice_type}.php", array(
'messages' => array_filter( $all_notices[ $notice_type ] ),
'notices' => array_filter( $all_notices[ $notice_type ] ),
) );
}
}
$fragments['notices_html'] = ob_get_clean();
wc_clear_notices();
return $fragments;
}
add_action( 'wc_ajax_ace_add_to_cart', 'ace_ajax_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_ace_add_to_cart', 'ace_ajax_add_to_cart_handler' );
remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 ); // Remove WC Core add to cart handler to prevent double-add
add_filter( 'woocommerce_add_to_cart_fragments', 'ace_ajax_add_to_cart_add_fragments' );
To enable Ajax add to cart for simple and variable products on Single product pages you need something different, building a custom Ajax add to cart function that handles also custom product fields and cart item data manipulation (what WooCommerce default Ajax add to cart doesn't allow).
Try the following fully tested on WooCommerce version 4.9.0:
add_action( 'wp_footer', 'single_product_ajax_add_to_cart_js_script' );
function single_product_ajax_add_to_cart_js_script() {
?>
<script>
(function($) {
$('form.cart').on('submit', function(e) {
e.preventDefault();
var form = $(this),
mainId = form.find('.single_add_to_cart_button').val(),
fData = form.serializeArray();
form.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } });
if ( mainId === '' ) {
mainId = form.find('input[name="product_id"]').val();
}
if ( typeof wc_add_to_cart_params === 'undefined' )
return false;
$.ajax({
type: 'POST',
url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'custom_add_to_cart' ),
data : {
'product_id': mainId,
'form_data' : fData
},
success: function (response) {
$(document.body).trigger("wc_fragment_refresh");
$('.woocommerce-error,.woocommerce-message').remove();
$('input[name="quantity"]').val(1);
$('.content-area').before(response);
form.unblock();
// console.log(response);
},
error: function (error) {
form.unblock();
// console.log(error);
}
});
});
})(jQuery);
</script>
<?php
}
add_action( 'wc_ajax_custom_add_to_cart', 'custom_add_to_cart_handler' );
add_action( 'wc_ajax_nopriv_custom_add_to_cart', 'custom_add_to_cart_handler' );
function custom_add_to_cart_handler() {
if( isset($_POST['product_id']) && isset($_POST['form_data']) ) {
$product_id = $_POST['product_id'];
$variation = $cart_item_data = $custom_data = array(); // Initializing
$variation_id = 0; // Initializing
foreach( $_POST['form_data'] as $values ) {
if ( strpos( $values['name'], 'attributes_' ) !== false ) {
$variation[$values['name']] = $values['value'];
} elseif ( $values['name'] === 'quantity' ) {
$quantity = $values['value'];
} elseif ( $values['name'] === 'variation_id' ) {
$variation_id = $values['value'];
} elseif ( $values['name'] !== 'add_to_cart' ) {
$custom_data[$values['name']] = esc_attr($values['value']);
}
}
$product = wc_get_product( $variation_id ? $variation_id : $product_id );
// Allow product custom fields to be added as custom cart item data from $custom_data additional array variable
$cart_item_data = (array) apply_filters( 'woocommerce_add_cart_item_data', $cart_item_data, $product_id, $variation_id, $quantity, $custom_data );
// Add to cart
$cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation, $cart_item_data );
if ( $cart_item_key ) {
// Add to cart successful notice
wc_add_notice( sprintf(
'%s %d × "%s" %s' ,
wc_get_cart_url(),
__("View cart", "woocommerce"),
$quantity,
$product->get_name(),
__("has been added to your cart", "woocommerce")
) );
}
wc_print_notices(); // Return printed notices to jQuery response.
wp_die();
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
All notices are enable and displayed on the fly:
Handling product custom fields and cart item data manipulation:
This custom Ajax add to cart code handle product custom fields, allowing to add them as custom cart item data.
For that we use woocommerce_add_cart_item_data WooCommerce dedicated hook enabled in our custom Ajax add to cart code, allowing to add product custom fields as custom cart item data or manipulate cart data on the fly.
If we add a product custom input text field with this code:
add_action( 'woocommerce_before_add_to_cart_button', 'product_additional_custom_fields' );
function product_additional_custom_fields() {
echo '<table class="variations" cellspacing="0" width="100px">
<tbody><tr>
<td class="label" style="width:100px"><label for="engraving">' . __("Engraving text") . '</label></td>
<td class="value">
<input type="text" name="engraving" id="engraving" value="" />
</td>
</tr></tbody>
</table>
</br>';
}
Then if you want to pass the field value as custom cart item data, you will use
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_custom_data', 10, 5 );
function add_cart_item_custom_data( $cart_item_data, $product_id, $variation_id = 0, $quantity, $custom_data = array() ) {
if ( isset($custom_data['engraving']) && ! empty($custom_data['engraving']) ) {
$cart_item_data['engraving'] = sanitize_text_field($custom_data['engraving']);
}
return $cart_item_data;
}
And you can check with the following, that will display in cart and checkout that custom cart item data:
add_filter( 'woocommerce_get_item_data', 'display_on_cart_and_checkout', 10, 2 );
function display_on_cart_and_checkout( $cart_data, $cart_item ) {
if ( isset($cart_item['engraving']) ) {
$cart_data[] = array(
"name" => __("Engraving text", "woocommerce"),
"value" => $cart_item['engraving']
);
}
return $cart_data;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Notes:
This code works on the fly as it is, but it's recommended to enqueue the jQuery code as an external file.
On some themes you should replace: $('.content-area').before(response); with $('.products').before(response);
to display the notices correctly…
Thanks for the helpful snippet, but the above code was not working for guest uses, but only for logins. The wc_fragment_refresh does not trigger when you log out And use it as a guest user.
$(document.body).trigger("wc_fragment_refresh");
Regards

Woocommerce - How to add additional fee based on selected radio option? [duplicate]

In Woocommerce, I have added two custom radio buttons on the checkout page and on click, I called an ajax function to add a delivery fee.
Here is my code:
$(document).on('change','#shipping_method_0_local_pickup5',function(e) {
$('.woocommerce-shipping-fields').css({
'display': 'none'
});
$("#deli").css("display","block");
var selected = $("input[type='radio'][name='post-del']:checked");
var selectedVal = selected.val();
var pickurl= "<?php echo admin_url('admin-ajax.php');?>?action=delivery";
$.ajax({
url: pickurl,
type: "POST",
data:{
input:selectedVal,
},
success: function(responseText)
{
jQuery(".order-total .woocommerce-Price-amount").html(responseText);
//$(".discount_code").css("display","block");
}
});
});
when the radio button click I want to add addition price $2 on my total.
add_action( 'wp_ajax_delivery', 'delivery' );
add_action( 'wp_ajax_nopriv_delivery', 'delivery' );
function delivery()
{
//My code
do_action( 'woocommerce_cart_calculate_fees', 'prefix_add_discount_line' ); // not working
exit;
}
Note: This is the hook which updates the code
add_action( 'woocommerce_cart_calculate_fees', 'prefix_add_discount_line' );
function prefix_add_discount_line( $cart ) {
$discount = $cart->subtotal + 2;
$cart->add_fee( __( 'Delivery', 'yourtext-domain' ) , +$discount );
}
You should give all necessary related code in your question. Remember that "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself".
So, in the code below, you will find a complete working solution, with additional custom radio buttons, that will add dynamically a delivery fee depending on the selected radio button and for "local pickup" shipping method.
The code (where you will need to define your targeted "local pickup" method ID):
// Enabling delivery options for a specific defined shipping method
function targeted_shipping_method(){
// HERE below define the shipping method Id that enable the custom delivery options
return 'local_pickup:5';
}
// Customizing Woocommerce checkout radio form field
add_action( 'woocommerce_form_field_radio', 'custom_form_field_radio', 20, 4 );
function custom_form_field_radio( $field, $key, $args, $value ) {
if ( ! empty( $args['options'] ) && is_checkout() ) {
$field = str_replace( '</label><input ', '</label><br><input ', $field );
$field = str_replace( '<label ', '<label style="display:inline;margin-left:8px;" ', $field );
}
return $field;
}
// Add a custom radio fields for packaging selection
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_form_delivery_addition', 20 );
function checkout_shipping_form_delivery_addition(){
$domain = 'wocommerce';
if ( WC()->session->get( 'chosen_shipping_methods' )[0] == targeted_shipping_method() ) :
echo '<tr class="delivery-radio"><th>' . __('Delivery options', $domain) . '</th><td>';
$chosen = WC()->session->get('chosen_delivery');
$chosen = empty($chosen) ? WC()->checkout->get_value('delivery') : $chosen;
$chosen = empty($chosen) ? 'regular' : $chosen;
// Add a custom checkbox field
woocommerce_form_field( 'radio_delivery', array(
'type' => 'radio',
'class' => array( 'form-row-wide' ),
'options' => array(
'regular' => __('Regular', $domain),
'premium' => __('Premium +'.wc_price(2.00), $domain),
),
'default' => $chosen,
), $chosen );
echo '</td></tr>';
endif;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_delivery_script' );
function checkout_delivery_script() {
// 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).val();
$.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' );
add_action( 'wp_ajax_nopriv_delivery', 'wc_get_delivery_ajax_data' );
function wc_get_delivery_ajax_data() {
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', 20, 1 );
function add_packaging_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Only for targeted shipping method
if ( WC()->session->get( 'chosen_shipping_methods' )[0] != targeted_shipping_method() )
return;
if( WC()->session->get( 'chosen_delivery' ) == 'premium' )
$cart->add_fee( __( 'Delivery fee', 'woocommerce' ), 2.00 );
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

How to add multiple products via checkbox at WooCommerce checkout (ajax)

So I have a script that I use to add a specific product to the cart when a checkbox is checked at checkout. AJAX is used to add and remove said product.
My question is, how can I cleanly and correctly manipulate this code to allow for an additional product to be added with a second checkbox. As in, say in the future I wanted the ability to add 1 or 2 extra "add-ons" how can I do this without duplicating code?
That is my current problem. I'm fairly decent at times, but often I find myself duplicating code knowing it has to be unnecessary. Any help appreciated (if you could explain a little bit it would be super appreciated. If not I can learn by examining the changes.)
// Display a custom checkout field
add_action( 'woocommerce_checkout_order_review', 'add_a_product1' , 10 );
function add_a_product1() {
$value = WC()->session->get('add_a_product');
woocommerce_form_field( 'cb_add_product', array(
'type' => 'checkbox',
'label' => ' ' . __('Add <span style="color:#ef4a23;">PRODUCT 1</span> for just <span style="color:#ef4a23;">$12.99?</span>'),
'class' => array('form-row-wide'),
), $value == 'yes' ? true : false );
}
// The jQuery Ajax request
add_action( 'wp_footer', 'checkout_custom_jquery_script' );
function checkout_custom_jquery_script() {
// Only checkout page
if( is_checkout() && ! is_wc_endpoint_url() ):
// Remove "ship_different" custom WC session on load
if( WC()->session->get('add_a_product') ){
WC()->session->__unset('add_a_product');
}
if( WC()->session->get('product_added_key') ){
WC()->session->__unset('product_added_key');
}
// jQuery Ajax code
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on( 'change', '#cb_add_product', function(){
var value = $(this).prop('checked') === true ? 'yes' : 'no';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'add_a_product',
'add_a_product': value,
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result);
}
});
});
});
</script>
<?php
endif;
}
// The Wordpress Ajax PHP receiver
add_action( 'wp_ajax_add_a_product', 'checkout_ajax_add_a_product' );
add_action( 'wp_ajax_nopriv_add_a_product', 'checkout_ajax_add_a_product' );
function checkout_ajax_add_a_product() {
if ( isset($_POST['add_a_product']) ){
WC()->session->set('add_a_product', esc_attr($_POST['add_a_product']));
echo $_POST['add_a_product'];
}
die();
}
// Add remove product
add_action( 'woocommerce_before_calculate_totals', 'adding_removing_specific_product' );
function adding_removing_specific_product( $cart ) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE the specific Product ID
$product_id = 2759;
if( WC()->session->get('add_a_product') == 'yes' && ! WC()->session->get('product_added_key') )
{
$cart_item_key = $cart->add_to_cart( $product_id );
WC()->session->set('product_added_key', $cart_item_key);
}
elseif( WC()->session->get('add_a_product') == 'no' && WC()->session->get('product_added_key') )
{
$cart_item_key = WC()->session->get('product_added_key');
$cart->remove_cart_item( $cart_item_key );
WC()->session->__unset('product_added_key');
}
}

WooCommerce extra fee on shipping cost if checkbox ship to other address is enabled

Is there an option that, say if a customer wants to ship to another address other than his billing address, can there be an extra fee based on that checkbox? I want that if a customer unchecks that checkbox, a extra fee of € 12.50 is added on the shipping cost. If anyone knows, please let me know :)
The checkbox is the default woocommerce checkbox btw.
I already fixed it by adding below code to the functions.php within your own theme:
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( 'ship_to_different_address' === $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', 'ship_to_different_address_script' );
function ship_to_different_address_script() {
// On checkoutpage
if( ( is_checkout() && ! is_wc_endpoint_url() ) ) :
?>
<script type="text/javascript">
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;
console.log('defined');
$('input[name=ship_to_different_address]').click( function(){
var fee = $(this).prop('checked') === true ? '1' : '';
$.ajax({
type: 'POST',
url: woocommerce_params.ajax_url,
data: {
'action': 'ship_to_different_address',
'ship_to_different_address': fee,
},
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_ship_to_different_address', 'get_ajax_ship_to_different_address' );
add_action( 'wp_ajax_nopriv_ship_to_different_address', 'get_ajax_ship_to_different_address' );
function get_ajax_ship_to_different_address() {
if ( isset($_POST['ship_to_different_address']) ) {
WC()->session->set('ship_to_different_address', ($_POST['ship_to_different_address'] ? '1' : '0') );
echo WC()->session->get('ship_to_different_address');
}
die();
}
// Add / Remove a custom fee
add_action( 'woocommerce_cart_calculate_fees', 'add_remove_ship_to_different_address', 10, 1 );
function add_remove_ship_to_different_address( $cart )
{
// Only on checkout
if ((is_admin() && !defined('DOING_AJAX')) || is_cart())
return;
$fee_amount = 12.50;
if (WC()->session->get('ship_to_different_address'))
$cart->add_fee(__('Shipping fee', 'woocommerce'), $fee_amount);
}

Categories