I want implement functionality on my site when user buy a x product then user will get a y product as free.
In my site i have variable products.If customer buy 1kg pack of X product then customer want to get Free 30ml of Y product.
I added below code in my function.php but its working the problem is when refreshing the page gift product count is increasing.
my updated code.
add_action( 'woocommerce_before_cart', 'bbloomer_apply_matched_coupons' );
function bbloomer_apply_matched_coupons() {
global $woocommerce;
$cat_in_cart = false;
foreach ( $woocommerce->cart->cart_contents as $key => $values ) {
// this is your product ID
$autocoupon = array( 123411 );
if( in_array( $values['variation_id'], $autocoupon ) ) {
$cat_in_cart = true;
break;
}
}
if ( $cat_in_cart ) {
$product_id = 2044;
$quantity = 1;
$variation_id = 2046;
$variation = array(
'pa_size' => '30ml'
);
$woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );
}
}
Add this to start of 'functions.php'.
ob_start();
session_start();
Then add this code.
add_action( 'woocommerce_before_cart', 'bbloomer_apply_matched_coupons' );
function bbloomer_apply_matched_coupons() {
if(!$_SESSION['GiftAdded']) {
global $woocommerce;
$cat_in_cart = false;
$coupon_in_cart = false;
$autocoupon = array( 123411 ); // variation ids of products that offers gifts
$freecoupon = array( 2046 ); // variation ids of products that are gift coupons
foreach ( $woocommerce->cart->cart_contents as $key => $values ) {
if( in_array( $values['variation_id'], $autocoupon ) ) {
$cat_in_cart = true;
}
if( in_array( $values['variation_id'], $freecoupon) ) {
$coupon_in_cart = true;
}
}
if ( $cat_in_cart && !$coupon_in_cart ) {
$product_id = 2044;
$quantity = 1;
$variation_id = 2046;
$variation = array( 'pa_size' => '30ml' );
$woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );
$_SESSION['GiftAdded']=true;
}
}
}
The $_SESSION['GiftAdded'] will prevent the gift product added again when its deleted manually.
There is an other alternative based on quantity using another hook… It handles when quantities are changed or products removed from cart and set the price of the free product to zero:
add_action( 'woocommerce_before_calculate_totals', 'add_free_product_to_cart', 20, 1 );
function add_free_product_to_cart( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$products_ids = array( 123411 ); // Products IDs to check
$free_var_id = 2046; // free product (variation ID)
$free_prod_id = 2044; // free product (product ID)
$free_attr = array( 'pa_size' => 'medium' ); // Free product attribute
$free_price = 0;
$targeted = $free = array('qty' => 0 ); // Initializing
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( in_array( $cart_item['data']->get_id(), $products_ids ) ) {
$targeted['qty'] += $cart_item['quantity'];
} elseif ( $cart_item['data']->get_id() == $free_var_id ) {
$cart_item['data']->set_price($free_price);
$free['qty'] += $cart_item['quantity'];
$free['key'] = $cart_item_key;
}
}
// We exit (No changes are needed)
if( $targeted['qty'] == $free['qty'] )
return;
if( $targeted['qty'] > 0 && $free['qty'] == 0 )
{
// Add the free product
$cart->add_to_cart( $free_prod_id, $targeted['qty'], $free_var_id, $free_attr );
}
elseif( $targeted['qty'] > 0 && $free['qty'] > 0 && $targeted['qty'] != $free['qty'] )
{
// Adjust free product quantity
$cart->set_quantity( $free['key'], $targeted['qty'] );
}
elseif( $targeted['qty'] == 0 && $free['qty'] > 0)
{
// Remove free product
$cart->remove_cart_item( $free['key'] );
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Related
This script is adding a fee if the product is in a particular category.
The script is working but only for one cart item.
But if there are 2 or more items it wil not multiply in the cart.
What am I doing wrong?
add_action( 'woocommerce_cart_calculate_fees','custom_pcat_fee', 20, 1 );
function custom_pcat_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// iPhone CAT
$iphone_categories = array('74');
$iphone_fee_amount = 0;
// iPad CAT
$ipad_categories = array('75');
$ipad_fee_amount = 0;
// Loop through cart items
foreach( $cart->get_cart() as $cart_item ){
$quantiy = $cart_item['quantity']; //get quantity from cart
if( has_term( $iphone_categories, 'product_cat', $cart_item['product_id']) )
$iphone_fee_amount = 4.70 * $quantiy;
if( has_term( $ipad_categories, 'product_cat', $cart_item['product_id']) )
$ipad_fee_amount = 2.60 * $quantiy;
}
// Adding the fee for iPhone
if ( $iphone_fee_amount > 0 ){
// Last argument is related to enable tax (true or false)
WC()->cart->add_fee( __( "Thuiskopieheffing iPhone", "woocommerce" ), $iphone_fee_amount, true );
}
// Adding the fee for iPad
if ( $ipad_fee_amount > 0 ){
// Last argument is related to enable tax (true or false)
WC()->cart->add_fee( __( "Thuiskopieheffing iPad", "woocommerce" ), $ipad_fee_amount, true );
}
}```
I think you missing basic summation in foreach. you override $iphone_fee_amount and $ipad_fee_amount you have to append each value to that variable. check the code below.
function custom_pcat_fee( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// iPhone CAT
$iphone_categories = array('74');
$iphone_fee_amount = 0;
// iPad CAT
$ipad_categories = array('75');
$ipad_fee_amount = 0;
// Loop through cart items
foreach( $cart->get_cart() as $cart_item ){
$quantiy = $cart_item['quantity']; //get quantity from cart
if( has_term( $iphone_categories, 'product_cat', $cart_item['product_id']) )
$iphone_fee_amount = $iphone_fee_amount + ( 4.70 * $quantiy );
if( has_term( $ipad_categories, 'product_cat', $cart_item['product_id']) )
$ipad_fee_amount = $iphone_fee_amount + ( 2.60 * $quantiy );
}
// Adding the fee for iPhone
if ( $iphone_fee_amount > 0 ){
// Last argument is related to enable tax (true or false)
WC()->cart->add_fee( __( "Thuiskopieheffing iPhone", "woocommerce" ), $iphone_fee_amount, true );
}
// Adding the fee for iPad
if ( $ipad_fee_amount > 0 ){
// Last argument is related to enable tax (true or false)
WC()->cart->add_fee( __( "Thuiskopieheffing iPad", "woocommerce" ), $ipad_fee_amount, true );
}
}
currently i can check if the cart contains categories (or a specific category) with this function..
function check_the_cart_for_categories() {
// holds checks for all products in cart to see if they're in our category
$category_checks = array();
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_in_cat = false;
if ( has_term( array('clothing', 'shoes','hats'), 'product_cat', $product->id ) ) {
#if ( has_term( 'clothing', 'product_cat', $product->id ) ) { //or for one
$product_in_cat = true;
}
array_push( $category_checks, $product_in_cat );
}
// if all items are in this category, do something
if ( ! in_array( false, $category_checks, true ) AND $ship_check ) {
echo "showmessage";
}
}
add_action( 'woocommerce_proceed_to_checkout' , 'check_the_cart_for_categories');
add_action( 'woocommerce_review_order_before_submit' , 'check_the_cart_for_categories');
but i want to check if the cart contains SHOES and HATS! (not any of them) ?
thank you!
Your code can be done but need to do fix some bugs. check my below code.
function check_the_cart_for_categories() {
// holds checks for all products in cart to see if they're in our category
$product_in_cat = false;
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term( 'shoes', 'product_cat', $product_id ) && has_term( 'hats', 'product_cat', $product_id ) ) {
$product_in_cat = true;
}
break;
}
// if all items are in this category, do something
if ( $product_in_cat ) {
echo "showmessage";
}
}
add_action( 'woocommerce_proceed_to_checkout', 'check_the_cart_for_categories' );
add_action( 'woocommerce_review_order_before_submit', 'check_the_cart_for_categories' );
UPDATE as per OP request. ( check both categories in cart )
function check_the_cart_for_categories() {
// Categories in a coma separated array
$must_categories = array('shoes','hats');
$fee_amount = 0;
$product_cat = array();
// Loop through cart items
foreach( $cart->get_cart() as $cart_item ){
$terms = get_the_terms( $cart_item['product_id'], 'product_cat' );
foreach ($terms as $term) {
$product_cat[] = $term->slug;
}
}
foreach ( $must_categories as $key => $must_cat ) {
if( in_array($must_cat, $product_cat) ){
$product_in_cat = true;
}else{
$product_in_cat = false;
break;
}
}
// if all items are in this category, do something
if ( $product_in_cat ) {
echo "showmessage";
}
}
add_action( 'woocommerce_proceed_to_checkout', 'check_the_cart_for_categories' );
add_action( 'woocommerce_review_order_before_submit', 'check_the_cart_for_categories' );
In WooCommerce, if the cart contains 6 or more items from 2 specific categories, then I would like to set a specific tax class (tax-zero) only to these items (not the entire cart, so not change it for the other products).
I use this piece of code which calculates the number of items in cart that are from the 2 categories, but I can't find how to complete it in order to set them with my "tax-zero" tax class.
add_action( 'woocommerce_before_calculate_totals', 'apply_conditionally_taxes', 20, 1 );
function apply_conditionally_taxes( $cart ){
$item_count = $cart->get_cart_contents_count();
$kingcat_count = 0;
foreach ( $cart->get_cart() as $cart_item ) {
if ( has_term( 'patisseries', 'product_cat', $cart_item['product_id'] ) or has_term( 'viennoiseries-et-gaufres', 'product_cat', $cart_item['product_id'] ) ) {
$kingcat_count += $cart_item['quantity'];
//echo $kingcat_count;
}
}
}
Code contains: (explanation added as a comment to the code)
Only count the items that belong to a certain category
Set a specific tax class to those items only
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
/* SETTINGS */
// Set categories
$categories = array ( 'patisseries', 'viennoiseries-et-gaufres' );
// Contains 6 or more items
$contains_min = 6;
/* END SETTINGS */
// Counter
$counter = 0;
// Loop trough
foreach ( $cart->get_cart() as $cart_item ) {
// Break loop
if ( $counter >= $contains_min ) {
break;
}
// Has term
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
// Add to counter
$counter += $cart_item['quantity'];
}
}
// Check
if ( $counter >= $contains_min ) {
// Loop trough
foreach( $cart->get_cart() as $cart_item ) {
// Has term
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
// We set "Zero rate" tax class
$cart_item['data']->set_tax_class( 'Zero rate' );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
In Woocommerce I am using woocommerce_product_get_price like to alter my product prices and it is working fine… But when I add to cart a product, the cart total and cart item are zero.
That is my code:
add_filter( 'woocommerce_add_cart_item', 'set_custom_cart_item_prices', 20, 2 );
function set_custom_cart_item_prices( $cart_data, $cart_item_key ) {
$new_price = $cart_data['data']->get_price() * 2;
$cart_data['data']->set_price( $new_price );
$cart_data['new_price'] = $new_price;
return $cart_data;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'set_custom_cart_item_prices_from_session', 20, 3 );
function set_custom_cart_item_prices_from_session( $session_data, $values, $key ) {
if ( ! isset( $session_data['new_price'] ) || empty ( $session_data['new_price'] ) )
return $session_data;
$session_data['data']->set_price( $session_data['new_price'] );
return $session_data;
}
Its doesn't work. I have also tried to use woocommerce_before_calculate_totals without success
How to avoid zero prices on cart? Any help is appreciated.
Updated: You are not using the correct hooks and the correct way. The following will replace all your code. The price changes will be done on simple products, variable products and product variations.
The 1st function is the rate to be applied to your product prices (so you will define in it your rate calculation).
The 2nd function will change all products displayed price on all product pages instead of using your custom function hooked in woocommerce_product_get_price filter hook.
The 3rd Function will change the products price in cart items, on cart and checkout pages and in orders items too.
// The price rate to be applied
function get_product_price_rate() {
// HERE define the price rate to be applied
return 1.25; // +25%
}
// Change the product displayed price on product pages
add_filter( 'woocommerce_get_price_html', 'custom_price_html', 10, 2 );
function custom_price_html( $price, $product ){
$rate = get_product_price_rate();
// Simple products and product variations
if( in_array( $product->get_type() , array( 'simple' , 'variation' ) ) ) {
$regular_price = wc_get_price_to_display( $product, array( 'price' => ( $product->get_regular_price() * $rate ) ) );
$active_price = wc_get_price_to_display( $product, array( 'price' => ( $product->get_price() * $rate ) ) );
if ( '' === $product->get_price() ) {
$price = apply_filters( 'woocommerce_empty_price_html', '', $product );
} elseif ( $product->is_on_sale() ) {
$price = wc_format_sale_price( $regular_price, $active_price ) . $product->get_price_suffix();
} else {
$price = wc_price( $active_price ) . $product->get_price_suffix();
}
}
// Variable products
elseif ( 'variable' === $product->get_type() ) {
$prices = $product->get_variation_prices( true );
if ( empty( $prices['price'] ) ) {
$price = apply_filters( 'woocommerce_variable_empty_price_html', '', $this );
} else {
$min_price = current( $prices['price'] ) * $rate;
$max_price = end( $prices['price'] ) * $rate;
$min_reg_price = current( $prices['regular_price'] ) * $rate;
$max_reg_price = end( $prices['regular_price'] ) * $rate;
if ( $min_price !== $max_price ) {
$price = wc_format_price_range( $min_price, $max_price );
} elseif ( $this->is_on_sale() && $min_reg_price === $max_reg_price ) {
$price = wc_format_sale_price( wc_price( $max_reg_price ), wc_price( $min_price ) );
} else {
$price = wc_price( $min_price );
}
$price .= $product->get_price_suffix();
}
}
return $price;
}
// Change cart items prices (and order items prices)
add_action('woocommerce_before_calculate_totals', 'increase_cart_item_prices', 100, 1 );
function increase_cart_item_prices( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop Through cart items
foreach ( $cart->get_cart() as $cart_item ) {
$rate = get_product_price_rate();
$cart_item['data']->set_price( $cart_item['data']->get_price() * $rate );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I need to create custom coupon type. Because i had custom calculation for custom coupon. Anyone out there help me.
Coupon calculation:
the cart has one product and value is 5000, then custom coupon code applied. The cart total need to change 2000. Similarly the cart has 2 product and value is 7000. If the custom coupon code applied, then cart total need to be 4000.
So the coupon need to make the cart total as flat 2000 for one product
In newer versions of WooCommerce, you will need to
Register a custom coupon type
Validate the coupon
Calculate & Apply the discount
Register custom coupon type
add_filter( 'woocommerce_coupon_discount_types', 'custom_coupon_type',10, 1);
function custom_coupon_type( $discount_types ) {
$discount_types['my_type'] =__( 'My New Coupon Type', 'woocommerce' );
return $discount_types;
}
Validate the coupon
add_filter('woocommerce_coupon_is_valid_for_product', 'validate_custom_coupon', 10, 4);
function validate_custom_coupon($valid, $product, $coupon, $values){
if ( ! $coupon->is_type( array( 'my_type' ) ) ) {
return $valid;
}
$product_cats = wp_get_post_terms( $product->id, 'product_cat', array( "fields" => "ids" ) );
// SPECIFIC PRODUCTS ARE DISCOUNTED
if ( sizeof( $coupon->product_ids ) > 0 ) {
if ( in_array( $product->id, $coupon->product_ids ) || ( isset( $product->variation_id ) && in_array( $product->variation_id, $coupon->product_ids ) ) || in_array( $product->get_parent(), $coupon->product_ids ) ) {
$valid = true;
}
}
// CATEGORY DISCOUNTS
if ( sizeof( $coupon->product_categories ) > 0 ) {
if ( sizeof( array_intersect( $product_cats, $coupon->product_categories ) ) > 0 ) {
$valid = true;
}
}
// IF ALL ITEMS ARE DISCOUNTED
if ( ! sizeof( $coupon->product_ids ) && ! sizeof( $coupon->product_categories ) ) {
$valid = true;
}
// SPECIFIC PRODUCT IDs EXLCUDED FROM DISCOUNT
if ( sizeof( $coupon->exclude_product_ids ) > 0 ) {
if ( in_array( $product->id, $coupon->exclude_product_ids ) || ( isset( $product->variation_id ) && in_array( $product->variation_id, $coupon->exclude_product_ids ) ) || in_array( $product->get_parent(), $coupon->exclude_product_ids ) ) {
$valid = false;
}
}
// SPECIFIC CATEGORIES EXLCUDED FROM THE DISCOUNT
if ( sizeof( $coupon->exclude_product_categories ) > 0 ) {
if ( sizeof( array_intersect( $product_cats, $coupon->exclude_product_categories ) ) > 0 ) {
$valid = false;
}
}
// SALE ITEMS EXCLUDED FROM DISCOUNT
if ( $coupon->exclude_sale_items == 'yes' ) {
$product_ids_on_sale = wc_get_product_ids_on_sale();
if ( isset( $product->variation_id ) ) {
if ( in_array( $product->variation_id, $product_ids_on_sale, true ) ) {
$valid = false;
}
} elseif ( in_array( $product->id, $product_ids_on_sale, true ) ) {
$valid = false;
}
}
return $valid;
}
Calculate & Apply Discount
add_filter('woocommerce_coupon_get_discount_amount', 'wc_cpn_disc', 10, 5);
function wc_cpn_disc($discount, $discounting_amount, $cart_item, $single, $coupon) {
// IF TYPE MATCHES PERFORM CUSTOM CALCULATION
if ($coupon->type == 'my_type')
$discount = $cart_item['quantity'] * 2000;
return $discount;
}
Sources:
#raju_odi's answer on this exact question
#Chris Morris's answer to Woocommerce custom coupon type with custom discount always return 0
Please use below code in your active theme's function.php
function custom_discount_type( $discount_types ) {
$discount_types['custom_discount'] =__( 'custom discount', 'woocommerce' );
return $discount_types;
}
// add the hooks
add_filter( 'woocommerce_coupon_discount_types', 'custom_discount_type',10, 1);
//function to get coupon amount for "custom_discount"
function woocommerce_coupon_get_discount_amount($discount, $discounting_amount, $cart_item, $single, $coupon) {
if ($coupon->code == 'custom'){
//echo "yes custom discount"; //if $coupon->type == 'fixed_cart' or 'percent' or 'fixed_product' or 'percent_product' The code Works
$discount = $cart_item['quantity'] * 2000;
return $discount;
} else {
return $discount;
}
}
//add hook to coupon amount hook
add_filter('woocommerce_coupon_get_discount_amount', 'woocommerce_coupon_get_discount_amount', 10, 5);
Note : Please add your added coupon name here on this line if ($coupon->code == 'your_added_coupon_here')
Working fine and tested.