The requirement:
Depending on the chosen payment option, certain checkout fields should not be required.
My scenario:
It clients select "local pickup" they get the option to select PayPal, credit card etc. and "pay at pickup".
If they pay at pickup, we don't need they payment address. The invoice will be handled at pickup and the checkout is actually a reservation.
I have found a solution myself and share this question as a reference.
Find the solution in an answer.
This is my solution:
add_action( 'woocommerce_checkout_process', 'gw_deactivate_some_fields_on_condition');
function gw_deactivate_some_fields_on_condition() {
add_filter( 'woocommerce_checkout_fields' , 'gw_some_billing_fields_not_required_for_cash_on_delivery_payment_method' );
}
function gw_some_billing_fields_not_required_for_cash_on_delivery_payment_method( $fields ) {
$chosen_payment_method = WC()->session->get('chosen_payment_method');
if ( 0 === strpos( $chosen_payment_method, 'cash_on_delivery' ) ) {
$fields['billing']['billing_address_1']['required'] = false;
$fields['billing']['billing_address_2']['required'] = false;
$fields['billing']['billing_city']['required'] = false;
$fields['billing']['billing_postcode']['required'] = false;
$fields['billing']['billing_country']['required'] = false;
$fields['billing']['billing_state']['required'] = false;
}
return $fields;
}
add_action( 'woocommerce_after_checkout_form', 'gw_disable_payment_fields_if_local_payment' );
function gw_disable_payment_fields_if_local_payment( $available_gateways ) {
?>
<script type="text/javascript">
jQuery( document ).ready(function() {
show_hide_payment_options();
});
jQuery('form.checkout').on('change','input[name^="payment_method"]',function() {
show_hide_payment_options();
});
jQuery('form.checkout').on('change','input[name^="shipping_method"]',function() {
show_hide_payment_options();
});
function show_hide_payment_options() {
var val = jQuery('input[name^="payment_method"]:checked').val(); // If it changed, then it must be the radio options so check the one that's selected
var fields_selector = '#billing_country_field, #billing_address_1_field, #billing_address_2_field, #billing_city_field, #billing_postcode_field';
if (val.match("^cash_on_delivery")) {
jQuery( fields_selector ).fadeOut();
} else {
jQuery( fields_selector ).fadeIn();
}
}
</script>
<?php
}
For handling the shipping fields see this post:
https://www.businessbloomer.com/woocommerce-hide-shipping-local-pickup-selected/
This was also a strong inspiration for my code.
Related
I need to override all states in WooCommerce checkout but I need to do this only for shipping section.
So "billing_state" is working fine with all current Italian states and I need to override only "shipping_state" with new states.
With code below will override both billing_states and also shipping states. How can I modify code in order to override "shipping_states"
Thanks in advance
add_filter( 'woocommerce_states', 'custom_woocommerce_states' );
function custom_woocommerce_states( $states ) {
$states['IT'] = array(
//I have to display only these 3 states in shipping Checkout
'TV' => 'Treviso',
'CA' => 'Carità',
'CS' => 'Castrette',
);
return $states;
}
This is what you are looking for. Add this to your active child themes functions.php
Refer to this WebToffee article
add_action( 'wp_footer', 'webtoffee_checkout_shipping_filter_it_states' );
function webtoffee_checkout_shipping_filter_it_states() {
if ( ! is_checkout() ) {
return;
}
?>
<script>
jQuery(document).ready(function($) {
$(document.body).on('country_to_state_changed', function() {
var $shipping_country = $('#shipping_country');
var new_shipping_state = '';
switch($shipping_country.val()) {
case 'IT':
new_shipping_state = {'TV': "Treviso", "CA": "Carità", "Cs": "Castrette"};
break;
}
if( ! $.isEmptyObject(new_shipping_state)) {
var optionsAsString = "";
for (var key in new_shipping_state) {
optionsAsString += "<option value='" + key + "'>" + new_shipping_state[key] + "</option>";
}
$( 'select[name="shipping_state"]' ).html( optionsAsString );
}
});
});
</script>
<?php
}
I am using the below code which works well to add a message to the woocommerce checkout when customers choose a country. But i also want to add a pop up using this shortcode
echo do_shortcode('[sg_popup id=3839] ');
But when i add it below the text message the pop up always shows, i.e. if i add the following
`echo '<div class="shipping-notice woocommerce-info" style="display:none">Please allow 5-10 business days for delivery after order processing.'; echo do_shortcode('[sg_popup id=3839] '); echo '</div>'
I imagine its because it is only hiding the code so it is actually running the shortcode? But what other options do I have?
Any help is appreciated.
add_action( 'woocommerce_before_checkout_billing_form', 'display_shipping_notice' );
function display_shipping_notice() {
echo '<div class="shipping-notice woocommerce-info" style="display:none">Please allow 5-10 business days for delivery after order processing.</div>';
}
add_action( 'woocommerce_after_checkout_form', 'show_hide_shipping_notice' );
function show_hide_shipping_notice(){
?>
<script>
jQuery(document).ready(function($){
// Set the country code (That will display the message)
var countryCode = 'FR';
$('select#billing_country').change(function(){
selectedCountry = $('select#billing_country').val();
if( selectedCountry == countryCode ){
$('.shipping-notice').hide();
}
else {
$('.shipping-notice').show();
}
});
});
</script>
<?php
}
The following code will show or hide a custom shipping notice depending on the chosen country (the code handle both billing and shipping country)…
To replace your shortcode, you can use instead a popup like using Sweet Alert 2 (a lightbox):
// Displaying a custom shipping notice
add_action( 'woocommerce_checkout_before_customer_details', 'checkout_country_shipping_notice' );
function checkout_country_shipping_notice() {
?>
<style>.shipping-notice.hidden{display:none;}</style>
<?php
$country = WC()->customer->get_shipping_country();
$country = empty($country) ? WC()->customer->get_billing_country() : $country;
$text = __("Please allow 5-10 business days for delivery after order processing.", "woocommerce" );
$class = 'woocommerce-info shipping-notice';
// Hidden if France or empty
if( empty($country) || $country == 'FR' )
$class .= ' hidden';
echo '<div class="'.$class.'">'.$text.'</div>';
}
// The jQuery code to show / hide the custom shipping notice
add_action( 'wp_footer', 'checkout_country_script' );
function checkout_country_script() {
// Only checkout page
if( is_checkout() && ! is_wc_endpoint_url() ):
?>
<script src="https://unpkg.com/sweetalert2#8.8.1/dist/sweetalert2.all.min.js"></script>
<script src="https://unpkg.com/promise-polyfill#8.1.0/dist/polyfill.min.js"></script>
<script type="text/javascript">
jQuery(function($){
var fc = 'form.checkout', sn = '.shipping-notice',
bc = 'select#billing_country', sc = 'select#shipping_country',
sda = 'input#ship-to-different-address-checkbox';
// Function that show hide the shipping notice
function showHideNotice(t){
if( $(t).val() == 'FR' || $(t).val() == undefined ){
$(sn).hide( function(){
$(this).removeClass('hidden');
});
} else {
$(sn).hide( 'fast', function(){
if( ! $(this).hasClass('hidden') )
$(this).addClass('hidden');
$(sn).show();
// Add a Sweet alert 2 popup
swal({
title: '<?php _e("Custom popup title", "woocommerce"); ?>',
text: '<?php _e("This is the text for my popup", "woocommerce"); ?>',
type: 'info' // can be: warning, error, success, info or question
});
});
}
}
// Billing and shipping country change
$(bc+','+sc).change(function(){
if($(sda).prop('checked'))
showHideNotice(sc);
else
showHideNotice(bc);
});
});
</script>
<?php
endif;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I'm trying to show/hide some elements from my checkout page, based on the chosen shipping method. The page elements I'm trying to show/hide come from another plugin, so I tried to change the display properties for them. I've looked to many thread like:
Show or hide checkout fields based on shipping method in Woocommerce 3
But it's for checkout fields, and I'm not sure how to do it for page elements.
Then based on this answer thread Here's my code so far:
add_action( 'wp_footer', 'conditionally_hidding_order_delivery_date' );
function conditionally_hidding_order_delivery_date(){
// Only on checkout page
if( ! is_checkout() ) return;
// HERE your shipping methods rate ID "Home delivery"
$home_delivery = 'distance_rate_shipping';
?>
<script>
jQuery(function($){
// Choosen shipping method selectors slug
var shipMethod = 'input[name^="shipping_method"]',
shipMethodChecked = shipMethod+':checked';
// Function that shows or hide imput select fields
function showHide( actionToDo='show', selector='' ){
if( actionToDo == 'show' )
$(selector).show( 200, function(){
$(this).addClass("validate-required");
});
else
$(selector).hide( 200, function(){
$(this).removeClass("validate-required");
});
$(selector).removeClass("woocommerce-validated");
$(selector).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
}
// Initialising: Hide if choosen shipping method is "Home delivery"
if( $(shipMethodChecked).val() != '<?php echo $home_delivery; ?>' ) {
showHide('hide','#e_deliverydate_field' );
showHide('hide','#time_slot_field' );
}
// Live event (When shipping method is changed)
$( 'form.checkout' ).on( 'change', shipMethod, function() {
if( $(shipMethodChecked).val() == '<?php echo $home_delivery; ?>' ) {
showHide('show','#e_deliverydate_field' );
showHide('show','#time_slot_field' );
}
else {
showHide('hide','#e_deliverydate_field' );
showHide('hide','#time_slot_field' );
}
});
});
</script>
<?php
}
But it's not working completely (the initializing function is not working.)
Any help is very much appreciated.
Additional edit:
<p class="form-row form-row-wide validate-required" id="e_deliverydate_field" data-priority="" style="display: block;"><label for="e_deliverydate" class="">Date<abbr class="required" title="required">*</abbr></label><span class="woocommerce-input-wrapper"><input class="input-text hasDatepicker" name="e_deliverydate" id="e_deliverydate" placeholder="Choose a Date" value="" style="cursor:text !important;" type="text"></span></p>
My objective is to change the display properties for p element from block to none, and vice versa.
The needed code is something much more simple, than the one used in my other answers, but you need to be sure that the targeted chosen shipping method is 'distance_rate_shipping' as I can't test it.
For initialization problem, see the solution exposed at the end of my answer.
The simplified needed code:
// Embedded jQuery script
add_action( 'wp_footer', 'checkout_delivery_date_script' );
function checkout_delivery_date_script() {
// Only checkout page
if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;
?>
<script type="text/javascript">
jQuery( function($){
var a = 'input[name^="shipping_method"]', b = a+':checked',
c = 'distance_rate_shipping',
d = '#e_deliverydate_field,#time_slot_field';
// Utility function that show or hide the delivery date
function showHideDeliveryDate(){
if( $(b).val() == c )
$(d).show();
else
$(d).hide('fast');
console.log('Chosen shipping method: '+$(b).val()); // <== Just for testing (to be removed)
}
// 1. On start
showHideDeliveryDate();
// 2. On live event "change" of chosen shipping method
$('form.checkout').on('change', a, function(){
showHideDeliveryDate();
});
});
</script>
<?php
}
Code goes in function.php file of your active child theme (or theme). It should work.
The initialization problem:
It's certainly because the plugin you are using that generates the delivery date output is delayed after initialization
The solution can be to add some delay on initialization execution.
So should try to replace this:
// 1. On start
showHideDeliveryDate();
By the following in my code (adjusting the execution delay to something higher or lower than 500):
// 1. On start
setTimeout(function(){
showHideDeliveryDate();
}, 500);
In Woocommerce, we are trying to add an additional cost to the order when is purchased via Paypal payment gateway.
We did it changing the price that is sent to Paypal this way:
add_filter('woocommerce_paypal_args', 'addition_pay');
function addition_pay($paypal_args){
$new_value=$paypal_args['amount_1']+10;
$paypal_args['amount_1']=$new_value;
return $paypal_args;
}
It works, but the problem is after the payment process, this additional cost is not reflected in Orders and email notifications.
Is this can be solved in some way? Any help is appreciated.
You should better add a fee based on payment gateway (here Paypal for you), like in the following:
// Add a fee of 10.00 when Paypal is chosen
add_action( 'woocommerce_cart_calculate_fees', 'custom_paypal_additional_fee', 20, 1 );
function custom_paypal_additional_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if( WC()->session->get( 'chosen_payment_method' ) == 'paypal' )
$cart->add_fee( __( 'Paypal fee', 'woocommerce' ), 10.00 );
}
// Add the information on checkout paypal text gateways section
add_filter('woocommerce_gateway_icon', 'custom_paypal_gateway_text', 20, 2 );
function custom_paypal_gateway_text( $html, $gateway_id ) {
if( $gateway_id == 'paypal' )
$html .= ' <small class="paypal-fee">(+ '.wc_price(10.00).')</small>';
return $html;
}
// Enable ajax update checkout event when choosing a gateway to refresh the fee
add_action('wp_footer', 'payment_gateways_update_checkout_event' );
function payment_gateways_update_checkout_event() {
?>
<script type="text/javascript">
(function($){
$('form.checkout').on( 'change', 'input[name^="payment_method"]', function() {
var t = { updateTimer: !1, dirtyInput: !1,
reset_update_checkout_timer: function() {
clearTimeout(t.updateTimer)
}, trigger_update_checkout: function() {
t.reset_update_checkout_timer(), t.dirtyInput = !1,
$(document.body).trigger("update_checkout")
}
};
$(document.body).trigger('update_checkout')
});
})(jQuery);
</script>
<?php
}
Code goes in function.php file of your active child theme (or active theme). Tested and work.
I am wondering if someone can help me with the following code. I am trying to set some conditional html dependent on which payment method the user selects on checkout. On the payment method page I am using the following function to update the payment method information:
function cart_update_script() {
if (is_checkout()) :
?>
<script>
jQuery( function( $ ) {
// woocommerce_params is required to continue, ensure the object exists
if ( typeof woocommerce_params === 'undefined' ) {
return false;
}
$checkout_form = $( 'form.checkout' );
$checkout_form.on( 'change', 'input[name="payment_method"]', function() {
$checkout_form.trigger( 'update' );
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'cart_update_script', 999 );
On the final checkout page I am then getting that selected payment method with this bit of code:
<?php $chosen_gateway = WC()->session->chosen_payment_method; ?>
Then I am using conditional statements like the following:
<?php if ( $chosen_gateway == 'stripe' ) { ?>
//do this
<?php } ?>
My problem is that I am not getting dynamic information when the user changes payment method. Sometimes the code works but sometimes it still thinks a different payment method was selected. Any help would be great!