Hide express paid shipping options when stock of the product is 0 or less than 0 (backorder cases) in Wocommerce checkout - wordpress

I set 2 methods of delivery:
Express shipping 48 hours at a cost which es a % of the total cart $ amount
Normal Free shipping in 29 days
The functionality that I want is the following:
If the stock of the product is = 0 or less than 0 (backorder is allowed), the Express shipping option should be hidden. Just must show the Normal free shipping option.
If the stock of the product is >0, both options should be shown.
If I selected more than one product, and one or more of the products does not have stock, the Express shipping option also should be hidden.
From another answer related to this question, I tried the script showed in the answer.
The problem is the following: in the last part of the script there is a mention to a variable in an external plugin.
How I adapt the code to a more generic woocommerce without that plugin?
Script:
/* !Hide Shipping Options Woocommerce */
add_filter( 'woocommerce_available_shipping_methods', 'hide_shipping_based_on_quantity' , 10, 1 );
function check_cart_for_oos() {
// load the contents of the cart into an array.
global $woocommerce;
$found = false;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
$_product_quantity = $_product->get_stock_quantity();
$_cart_quantity = $values['quantity'];
if (($_product_quantity <= 0) || ($_cart_quantity > $_product_quantity)) {
$found = true;
break;
}
}
return $found;
}
function hide_shipping_based_on_quantity( $available_methods ) {
// use the function check_cart_for_oos() to check the cart for products with 0 stock.
if ( check_cart_for_oos() ) {
// remove the rate you want
unset( $available_methods['table_rate_shipping_next-day'] ); // Replace "table_rate_shipping_next-day" with "table_rate_shipping_your-identifier".
}
// return the available methods without the one you unset.
return $available_methods;
}
From: Remove next day shipping method for out of stock items in Woocommerce

In that answer, it's already mentioned to use your own shipping method identifier. So you just need to replace the shipping method identifier with yours.
// use the function check_cart_for_oos() to check the cart for products with 0 stock.
if ( check_cart_for_oos() ) {
// remove the rate you want
unset( $available_methods['USE_YOUR_OWN_IDENTIFIER_HERE'] ); // Replace "table_rate_shipping_next-day" with "table_rate_shipping_your-identifier".
}

Related

make a coupon that discount based on weight

I have been trying to make a Coupon that makes a discount based on the cart weight when a coupon is used.
I have achieved something using a fixed amount coupon (with fixed value zero) and adding fees :
$cart_weight = $cart->get_cart_contents_weight() ;
and
$cart->add_fee( 'Discount ' . $coupon_code, $cost* -1 , false );
Even it works ,I dont like this, I would like to have it as a regular coupon. Is there any way? Thanks
Sure, it's possible, you only have to create a unique coupon and apply it to the cart instead of adding a negative fee
//ADD coupon based of cart weight
add_action( 'woocommerce_before_calculate_totals', 'generate_coupon_based_on_total_weight' );
function generate_coupon_based_on_total_weight( $cart ) {
// Set the threshold weight for applying the coupon
$threshold_weight = 10;
$discount_amount = 2;
$coupon_prefix = 'weight_';
$total_weight = $cart->get_cart_contents_weight() ;
// Check if the total weight is greater than or equal to the threshold weight
if ( $total_weight >= $threshold_weight ) {
// Check if the coupon code with the "weight_" prefix has already been applied
if ( has_coupon_code_with_prefix( $coupon_prefix ) ) {
// Coupon code already applied, do nothing
return;
}
// Generate a unique coupon code
$coupon_code = uniqid( $coupon_prefix );
// Create a new coupon object
$coupon = new WC_Coupon();
$coupon->set_code( $coupon_code );
$coupon->set_amount( $discount_amount ); // Set the coupon amount
$coupon->set_individual_use( true ); // Set the coupon to be used only once
$coupon->set_usage_limit( 1 ); // Set the usage limit to 1
$coupon->save(); // Save the coupon
// Apply the coupon to the cart
$cart->add_discount( $coupon_code );
} else {
// Total weight is less than the threshold, remove the coupon if it exists
remove_coupon_from_cart( $coupon_prefix );
}
}
function has_coupon_code_with_prefix( $prefix ) {
// Get the applied coupons
$applied_coupons = WC()->cart->get_applied_coupons();
// Check if there are any applied coupons
if ( ! empty( $applied_coupons ) ) {
// Iterate through the applied coupons
foreach ( $applied_coupons as $coupon_code ) {
// Check if the coupon code starts with the specified prefix
if ( strpos( $coupon_code, $prefix ) === 0 ) {
// There is a coupon code applied that starts with the specified prefix
return true;
}
}
}
// No coupon code was found that starts with the specified prefix
return false;
}
function remove_coupon_from_cart($prefix) {
global $woocommerce;
// Get the cart object
$cart = $woocommerce->cart;
// Get the coupon codes applied to the cart
$coupon_codes = $cart->get_coupons();
// Loop through the coupon codes and remove any that start with the specified prefix
foreach ($coupon_codes as $code => $coupon) {
if (strpos($code, $prefix) === 0) {
$cart->remove_coupon($code);
// Save the updated cart
$cart->calculate_totals();
}
}
}
The main idea of this function is to apply a discount coupon to the user's cart if the total weight of the products in the cart meets a certain threshold, and to remove the coupon if the total weight falls below the threshold.
The function is triggered by the woocommerce_before_calculate_totals action, which occurs before the total cost of the products in the cart is calculated.
The function first sets a few variables:
$threshold_weight: This is the weight that the total weight of the products in the cart must meet or exceed in order for the coupon to be applied.
$discount_amount: This is the amount of the discount that will be applied if the coupon is applied.
$coupon_prefix: This is a prefix that will be added to the coupon code to make it unique.
The function then calculates the total weight of the products in the cart using the get_cart_contents_weight method.
Next, the function checks if the total weight is greater than or equal to the threshold weight. If it is, the function generates a unique coupon code using the uniqid function and the $coupon_prefix variable, and creates a new coupon object using the WC_Coupon class. The coupon object is then configured with the discount amount, individual use, and usage limit. Finally, the coupon is saved and applied to the cart using the add_discount method.
If the total weight is less than the threshold weight, the function removes the coupon from the cart if it exists by calling the remove_coupon_from_cart function and passing in the $coupon_prefix variable.
Overall, this function allows you to apply a discount coupon to the user's cart if the total weight of the products in the cart meets a certain threshold, and to remove the coupon if the total weight falls below the threshold.

WooCommerce Distance Rate Shipping causing tax rate to reset

I am on the verge of losing it with this problem. So what I am attempting is to apply Zero rate tax rate when a specific coupon ('12345') is applied to the order. This site also has the plugin WooCommerce Distance Rate Shipping installed which adds its own costs and tax to the order based on billing distance.
While the billing address fields are empty, the following code successfully detects the coupon in question and sets tax rate to 'Zero Rate':
function apply_matched_coupons() {
$coupon_code = '12345';
if ( !is_admin() && WC()->cart->has_discount( $coupon_code ) ) {
$tax_class = 'Zero rate';
}
return $tax_class;
};
add_action( 'woocommerce_product_tax_class','apply_matched_coupons' );
But when an address is typed in the billing fields, the Woocommerce order update AJAX works and the WooCommerce Distance Rate Shipping plugin reads the billing addresss, re-checks its rules, applies its costs and also adds its tax. Hence, overwriting my Zero Tax rate set earlier. Screenshot is attached. I believe a hook like woocommerce_checkout_update_order_review may work which fires each time the order is updated on checkout, but can't figure out exactly how to set it.
The plugin's page here does show an example to set the $rule_cost to 0 with this code:
add_filter( 'woocommerce_distance_rate_shipping_rule_cost_distance_shipping', function( $rule_cost, $rule, $distance, $package ) {
$order_total = $package['contents_cost'];
if ( $order_total > 100 && $distance <= 5 ) {
$rule_cost = 0;
}
return $rule_cost;
}, 10, 4 );
Could this help in any way?
screenshot of extra tax added by the said plugin

Troubleshooting Woocommerce order emails customized according to shipping method

Currently my two options for shipping are regular shipping (using the Flexible Shipping plugin) and local pickup. I would like my Completed Order emails to be customized according to the shipping method used for the order (e.g. I'd like the header to say "We've shipped your order!" for regular shipping and "Your order is ready for pickup!" for local pickup).
Here's my first attempt at modifying the text through my child theme's functions.php (code based on LoicTheAztec answer in this thread). Currently, instead of inserting the desired text, it shows the default text that I entered in Woocommerce>Settings>Emails>Order Completed>Completed order>Email heading, regardless of shipping method selected.
add_action( 'woocommerce_email_header ', 'modify_header_by_shipping', 10, 2 );
function modify_header_by_shipping( $email_heading, $email ) {
// Only modify "Customer Completed Order" email notification
if( 'customer_completed_order' != $email->id ) return;
//Initialize variable
$found = false;
// Get $order object from $email
$order = $email->object;
// Iterating through Order shipping methods
foreach($order->get_shipping_methods() as $value){
$rate_id = $value->get_method_id(); // Get the shipping rate ID
if ( 'shipping_method_0_local_pickup5' == $rate_id )
$found = true;
}
if ($found)
echo '<p>'.__("Your order is ready for pickup!","woocommerce").'</p>';
else
echo '<p>'.__("We've shipped your order!","woocommerce").'</p>';
}
Here's my ordering page: https://carrickseeds.ca/checkout/

Disable a woocommerce delivery method on weekends and cut off time in the week

Based on Hide specific shipping method depending on day time in WooCommerce answer code, I am looking to only allow Monday to Friday before 3pm.
//hide shipping method based on time
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_time', 10, 2 );
function hide_shipping_method_based_on_time( $rates, $package )
{
// Set your default time zone (http://php.net/manual/en/timezones.php)
date_default_timezone_set('Europe/London');
// Here set your shipping rate Id
$shipping_rate_id = 'flat_rate:29';
// When this shipping method is available and after 2 PM
if ( array_key_exists( $shipping_rate_id, $rates ) && date('H') > 14 ) {
unset($rates[$shipping_rate_id]); // remove it
}
return $rates;
}
You will use the date() function with N parameter to handle the day of the week and H parameter to handle hours as follow to disable a specific shipping method on weekends and after 3 PM the weekdays:
// Hide shipping method based on the day of the week and time
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_day_of_the_week_and_time', 10, 2 );
function hide_shipping_method_based_on_day_of_the_week_and_time( $rates, $package )
{
// Set your default time zone (http://php.net/manual/en/timezones.php)
date_default_timezone_set('Europe/London');
// Here set your shipping rate Id
$shipping_rate_id = 'flat_rate:29';
// When this shipping method is available and after 2 PM
if ( array_key_exists( $shipping_rate_id, $rates )
&& ! ( date('H') <= 15 && ! in_array(date('N'), [6,7]) ) ) {
unset($rates[$shipping_rate_id]); // remove it
}
return $rates;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Clearing shipping caches:
You will need to empty your cart, to clear cached shipping data
Or In shipping settings, you can disable / save any shipping method, then enable back / save.

woocommerce tiered flat rate based on a custom field

I have a website where customer chooses a zone in a dropdown in billing fields. These are 4 zones: zone1, zone2 and zone3 as an example.
The idea is that if customer chose zone1 and total cart is less than $1000, customer needs to pay a shipping rate of $100. If more than $1000, customer gets free shipping.
I need to replicate that for the other 2 zones with different cart amounts and shipping rates. Is this possible?
Right now, I have the following working code but customer has to manually choose a flat rate. Problem is, of course, customers... If free shipping is displayed, they will choose that one knowing they dont apply for that option when total amount is less for their zone.
/* Change shipping based on total cost purchased. */
add_filter( 'woocommerce_package_rates', 'bbloomer_woocommerce_tiered_shipping', 10, 2 );
function bbloomer_woocommerce_tiered_shipping( $rates, $package ) {
$threshold_centro = 1000;
$threshold_hasta_el_5 = 1500;
$threshold_arelauquen = 2000;
if ( WC()->cart-> cart_contents_total < $threshold_centro ) {
unset( $rates['free_shipping:9'] );
}
elseif ( WC()->cart-> cart_contents_total < $threshold_hasta_el_5 ) {
unset( $rates['flat_rate:2'] );
}
elseif ( WC()->cart-> cart_contents_total < $threshold_arelauquen ) {
unset( $rates['flat_rate:2'], $rates['flat_rate:3'] );
}
else {
unset( $rates['flat_rate:2'], $rates['flat_rate:3'], $rates['flat_rate:4'], $rates['flat_rate:5'], $rates['flat_rate:6'] );
}
return $rates;
}
and the custom field is this one: billing_wcccf_id_qXZZegrC774HULq
Try to set a WC session when you trigger the selectbox and the use it in your if statement to get the right shipping rate or use a switch
WC->session->set('your session name', 'value')
WC->session->get('your session')

Resources