I'm having trouble showing the ID of the product that I have in the cart, to perform a verification at the time of shipping.
I have the following code:
add_filter( 'woocommerce_package_rates', 'c7_hide_free_shipping_class', 10, 2 );
function c7_hide_free_shipping_class( $rates, $package ) {
echo $in_cart = false;
global $woocommerce;
$product = wc_get_product( $product_id );
$state = $woocommerce->customer->get_billing_state();
$city = explode(' - ', $woocommerce->customer->get_billing_city());
$distrito = '';
if (count($city) > 1) {
$distrito = $city[1];
}
if ($state != 'LMA' ||
!in_array($distrito, ['Surquillo'])
) {
unset( $rates['SD'] );
unset( $rates['ND'] );
}
if ($state == 'LMA' &&
in_array($distrito, ['Chorrillos'])
) {
$rates['flat_rate:7']->cost += 0; // 7.5
$rates['flat_rate:7']->label = 'De 1 a 2 dias';
} else if ($state == 'LMA' && $product == '6721' &&
in_array($distrito, ['Chaclacayo'])
) {
$rates['flat_rate:7']->cost += 9.5; // 17.50
$rates['flat_rate:7']->label = 'De 2 a 3';
//Fin Prueba
} else if ($state == 'LMA' &&
in_array($distrito, [])
){
unset( $rates['flat_rate:7'] );
}
return $rates;
}
I am trying to get Product ID: 6721 to have a different shipping price than other products. That is, if I put it in the cart and I am about to buy a product, eg "Chair", it has a different shipping price than other products. I am trying to do it by code since it is structured for those districts in code.
Chorrillos District has a different shipping price for all products, on the other hand, the Chaclacayo District has another price only if the shipment is with ID 6721, but it does not let me, it does not change the price of the shipment and only shows the default shipment when it should to show 17.50. Any way to verify the product ID when buying? I already appreciate any help.
Related
I need to remove / disable the coupon effect for products discounted by more than 10%.
At the moment I have something like this:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$excluded_categories = array( 'prod_category_name' );
// Initialize
$coupon_flag = false;
// Loop through applied coupons
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'percent_product' ) ) ) {
$coupon_flag = true;
break;
}
}
foreach( $cart->get_applied_coupons() as $coupon_code ) {
// Get the WC_Coupon object
$coupon = new WC_Coupon($coupon_code);
$coupon_amount = $coupon->get_amount(); // Get coupon amount
}
if ( $coupon_flag ) {
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get product ID in
$product_id = $cart_item['product_id'];
// NOT contains the definite term
if ( ! has_term( $excluded_categories, 'product_cat', $product_id ) ) {
// Get regular price
$regular_price = $cart_item['data']->get_regular_price();
// Get promo price
$promo_price = $cart_item['data']->get_price();
// Zniżka
$discount = 100 - (($promo_price * 100) / $regular_price);
$percentage = 10;
$percent_price = $regular_price - ($regular_price * ($percentage / 100));
if ($discount > $coupon_amount ) {
//$coupon->set_amount(0);
$cart->remove_coupon( 'coupon_name' );
}
if ( $percent_price < $promo_price ) {
$cart_item['data']->set_price( $regular_price );
} else {
$cart_item['data']->set_price( $promo_price );
}
}
}
}
}
At the moment, the code removes the coupon for the entire cart:
$cart->remove_coupon( 'coupon_name' );
Is there an option to remove the discount for the selected product from the cart?
I need something like:
$cart_item['data']->remove_coupon( 'coupon_name' );
Thank you so much!
Ok I added filter and it works perfect =)
add_filter( 'woocommerce_coupon_is_valid_for_product', 'exclude_product_from_product_promotions_frontend', 9999, 4 );
function exclude_product_from_product_promotions_frontend( $valid, $product, $coupon, $values ) {
$regular_price = $product->get_regular_price();
$promo_price = $product->get_price();
$discount = 100 - (($promo_price * 100) / $regular_price);
$coupon_amount = 10;
if ($discount > $coupon_amount ) {
$valid = false;
}
return $valid;
}
When a coupon is applied (belonging to a certain type) I change the product discount price to the regular price via:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_object) {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$coupon = False;
if ($coupons = WC()->cart->get_applied_coupons() == False )
$coupon = False;
else {
foreach ( WC()->cart->get_applied_coupons() as $code ) {
$coupons1 = new WC_Coupon( $code );
if ($coupons1->type == 'percent_product' || $coupons1->type == 'percent')
$coupon = True;
}
}
if ($coupon == True)
foreach ( $cart_object->get_cart() as $cart_item )
{
$price = $cart_item['data']->regular_price;
$cart_item['data']->set_price( $price );
}
}
But if I have a category excluded, the code freaks out because it changes the price from sale to regular in the cart and does not add a discount.
How to work around this so that the excluded category does not change to the regular price?
To exclude certain categories you can use has_term() when loop through the cart items
So you get:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$excluded_categories = array( 63, 15, 'categorie-1' );
// Initialize
$coupon_flag = false;
// Loop through applied coupons
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'percent_product' ) ) ) {
$coupon_flag = true;
break;
}
}
// True
if ( $coupon_flag ) {
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get product ID in
$product_id = $cart_item['product_id'];
// NOT contains the definite term
if ( ! has_term( $excluded_categories, 'product_cat', $product_id ) ) {
// Get regular price
$regular_price = $cart_item['data']->get_regular_price();
// Set new price
$cart_item['data']->set_price( $regular_price );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
I'm trying to drop the VAT on my cart items when the subtotal is over a specific amount. But when I use WC()->cart->get_subtotal() to get the subtotal price, it returns 0 and my if statement fails.
add_action( 'woocommerce_product_get_tax_class', 'wp_check_uk_vat', 1, 2 );
function wp_check_uk_vat( $tax_class, $product ) {
$cart_total = WC()->cart->get_subtotal();
// echo $cart_total;
if( $cart_total >= 100 ) {
$tax_class = "Zero rate";
}
return $tax_class;
}
Similar code is used here: https://docs.woocommerce.com/document/setting-up-taxes-in-woocommerce/#section-18
The goal of the code is to drop the VAT on the cart (not shipping) when the order amount is over 135 GBP (to comply with the new Brexit rules for merchants).
Because WC()->cart->get_subtotal() returns 0, the if statement fails, and the VAT is not being dropped.
Try this
add_action( 'woocommerce_product_get_tax_class', 'wp_check_uk_vat', 1, 2 );
function wp_check_uk_vat( $tax_class, $product ) {
if(WC()->cart){
$subtotal = 0;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$subtotal += $cart_item[ 'data' ]->get_price( 'edit' ) * $cart_item[ 'quantity' ];
}
if ( $subtotal >= 100 ) {
$tax_class = "Zero rate";
}
}
return $tax_class;
}
The discount I currently have essentially says
If 6 products within a specific category are in the cart --- discount the total price of $10
This piece of the code works fine. My issue is, this does not work
If there are 7 products, the 7th product being from a different category.
My goal is to give the discount no matter how many products are in the cart so long as there are 6 products within "Category A".
The following code works so long as there is 6 products in the "discounted category" or there is 1 product with a quantity of 6 etc. It falls apart when I add a product from another category. Feel free to rip it apart.
add_action( 'woocommerce_before_calculate_totals', 'this_item_free' );
function this_item_free() {
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$valid_product_category_id = array('soup-mix');
$has_category = false;
$count = WC()->cart->get_cart_contents_count();
foreach ( WC()->cart->get_cart() as $product ) {
$quantity = $product['quantity'];
$price = $product['data']->get_price();
}
if ( has_term( $valid_product_category_id, 'product_cat', $product['product_id'],
$product['quantity'] ) ) {
$has_category = true;
$cart_total = floatval( preg_replace( '#[^\d.]#', '', WC()->cart->get_cart_total() ) );
if($count == 6 && $has_category = true){
add_action( 'woocommerce_cart_calculate_fees', 'discount_based_on_total', 25, 1 );
function discount_based_on_total( $cart ) {
$total = $cart->cart_contents_total;
$discount = 9.95;
$cart->add_fee( __('discount', 'woocommerce'), -$discount );
wc_add_notice( apply_filters( 'discount_applied', 'You just got a free soup!') );
}
}
}
}
Your code contains some unnecessary steps and what you want to achieve can be obtained with just the woocommerce_cart_calculate_fees action hook
My answer contains:
Give a discount no matter how many products are in the cart so long as there are 6 products or there is 1 product with a quantity of 6, etc.. within "Category A".
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
/* SETTINGS */
// Specific categories
$specific_categories = array( 'Categorie-A' );
// Discount
$discount = 10;
// Min quantity
$minimun_quantity = 6;
/* END SETTINGS */
// Counter
$current_quantity = 0;
// Loop though each cart item
foreach ( $cart->get_cart() as $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
// Has certain category
if ( has_term( $specific_categories, 'product_cat', $product_id ) ) {
// Quantity
$product_quantity = $cart_item['quantity'];
// Add to total
$current_quantity += $product_quantity;
}
}
// Greater than or equal to
if ( $current_quantity >= $minimun_quantity ) {
// Add fee
$cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
To apply the discount per 6 products (6 = $10, 12 = $20, 18 = $30, etc..)
Replace
// Greater than or equal to
if ( $current_quantity >= $minimun_quantity ) {
// Add fee
$cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );
}
With
// Greater than or equal to
if ( $current_quantity >= $minimun_quantity ) {
// Modulo
$mod = $current_quantity % $minimun_quantity;
// Times it fit
$times = ( $current_quantity - $mod ) / $minimun_quantity;
// Discount * times
$discount = $discount * $times;
// Add fee
$cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );
}
My woocommerce products are actually cruise expeditions (two products = two expedition types). For each product, the variations consists of the weeks in which cruises take place (= dates).
So I have Ligurian Sea Expeditions with 20 different weeks and Greece Expeditions with other 20 weeks. Fortunately I have just 2 products like that to deal with (a very simple situation)
The customer usually chooses one week expedition. However I need to apply a 10% discount on the second (or third) week in case a customer decides to apply for > 1 week. Hence the first week is paid full price, but the second and (in case there is) the third week will be discounted 10%.
I have come out with a function that enables to apply the discount in the case of two weeks.
function cart_discount() {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
global $woocommerce; $cat_count = 0;
$cart = WC()->cart->get_cart();
foreach($cart as $cart_item_key => $values) {
$product_id = $values['product_id']; // product ID (= cruise type)
$variation_id = $values['variation_id']; // variation (=week)
$cart_lines_total = $values["line_total"]; //variation total price
$cart_lines_quantity = $values["quantity"];// variation quantity
//$product = 1394 = Expedition Ligurian eng
//$product = 1389 = Expedition Greece eng
//$product = 13888 = Expedition Ligurian ita
//$product = 13910 = Expedition Greece ita
//I hereby add a condition as we do have the same cruises with students prices which are not eligible to this discount (and are stored with different product_id)
if($product_id == '1394' || $product_id == '1389' || $product_id == '13888' || $product_id == '13910')
{
//put in a new array only the terms I need for the calculation later
$cart_array []= array( $product_id , $variation_id, $cart_lines_quantity, $cart_lines_total);
}
}
// discount percent is 10%
$percent = -0.10;
if ($cart_array[0][0] == $cart_array[1][0]) //if in the cart the same product is present two times
{
$discount = $percent * $cart_array[1][2] * $cart_array[1][3];
$discount_text = __( 'Quantity discount', 'woocommerce' );
WC()->cart->add_fee( $discount_text, $discount, false );
}
}
add_action( 'woocommerce_cart_calculate_fees','cart_discount' );
This code has many limitations as I said before, as it doesn't take in acccount some scenarios such as:
1) it deals only if in the cart tere are only two variations of the same product: in case a customer decides for x weeks to be purchased I should be able to check if the same product is present with > 2 variations;
2) It doesn't take into account the possibility having the two products with 2 ore more variations (ie.a person buying let's say two weeks in Ligurian Sea and two weeks in Greece)
If somebody can help me in improving the code I wrote I would be very happy!!
Just to make sure i got it right, you want to apply a discount if the customer buys more than 1 variation of the same product. Correct?
Here is the final code I wrote (it works, I have tested it)
function cart_discount() {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
global $woocommerce;
$cart = WC()->cart->get_cart();
$has_coupons = count(WC()->cart->applied_coupons)>0?true:false;
if(!$has_coupons) //verifies that other discounts are not added
{
foreach($cart as $cart_item_key => $values) {
$product_id = $values['product_id']; // product ID
$variation_id = $values['variation_id']; // product quantity
$cart_lines_total = $values["line_total"];
$cart_lines_quantity = $values["quantity"];
//products for which this kind of discount must be applicable:
//$product_id = 1394 = Spedizioni CSR eng
//$product_id = 1389 = Spedizioni IDP eng
//$product_id = 13888 = Spedizioni CSR ita
//$product_id = 13910 = Spedizioni IDP ita
if($product_id == '1394' || $product_id == '1389' || $product_id == '13888' || $product_id == '13910')
{
$cart_array []= array( $product_id , $variation_id, $cart_lines_quantity, $cart_lines_total);
}
}
$conteggio = count($cart_array); //conta il numero di prodotti nel carrello
// percent is 10%
$percent = -0.10;
if ($conteggio < 3 && $cart_array[0][0] == $cart_array[1][0])
{
$discount = $percent * $cart_array[1][3];
$discount_text = __( '10% discount on subsequent week(s)', 'woocommerce' );
WC()->cart->add_fee( $discount_text, $discount, false );
}
if ($conteggio < 4 && $cart_array[0][0] == $cart_array[1][0] && $cart_array[0][0] == $cart_array[2][0])
{
$discount = ($percent * $cart_array[1][3]) + ($percent * $cart_array[2][3]);
$discount_text = __( '10% discount on subsequent week(s)', 'woocommerce' );
WC()->cart->add_fee( $discount_text, $discount, false );
}
if ($conteggio < 5 && $cart_array[0][0] == $cart_array[1][0] && $cart_array[0][0] == $cart_array[2][0] && $cart_array[0][0] == $cart_array[3][0])
{
$discount = ($percent * $cart_array[1][3]) + ($percent * $cart_array[2][3]) + ($percent * $cart_array[3][3]);
$discount_text = __( '10% discount on subsequent week(s)', 'woocommerce' );
WC()->cart->add_fee( $discount_text, $discount, false );
}
} else return;
}
add_action( 'woocommerce_cart_calculate_fees','cart_discount' );
As you see, I had to specify the product_id of the products that are interested in this particular kind of discount, which is fine for me, although it would be nicier if we could set it to categories (I didn't have the time to develop that condition)
Secondly, the part I don't like is the following
if ($conteggio < 3 && $cart_array[0][0] == $cart_array[1][0])
and all the following conditions: I was looking for a function that may go through the $cart_array and find the relations thta I set manually in each if() condition.
Thanks