I want to add percentage value to cart item prices based on the selected payment gateway.
The problem I am facing is variation product price is not updating for the product price. Initially selected price is showing all the time.
How can I get the changed price accordingly?
My code so far:
// Set custom cart item price
function add_custom_price( $cart ) {
// This is necessary for WC 3.0+
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Avoiding hook repetition (when using price calculations for example | optional)
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
$chosen_payment_method = WC()->session->get('chosen_payment_method');
if($chosen_payment_method == 'cod') {
$increaseby = 3;
} elseif($chosen_payment_method == 'paypal') {
$increaseby = 8;
} else {
$increaseby = 10;
}
$price = get_post_meta($cart_item['product_id'] , '_price', true);
$price = $price + (($price * $increaseby)/100);
$cart_item['data']->set_price( $price );
}
}
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 1000, 1);
Any help highly appreciated.
There are some mistakes in your code
Use WC()->session->get( 'chosen_payment_method' ); outside the foreach loop
get_post_meta() is not needed to get the price, you can use get_price()
You will also need jQuery that is triggered when changing the payment method.
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;
// Get payment method
$chosen_payment_method = WC()->session->get( 'chosen_payment_method' );
// Compare
if ( $chosen_payment_method == 'cod' ) {
$increaseby = 3;
} elseif ( $chosen_payment_method == 'paypal' ) {
$increaseby = 8;
} else {
$increaseby = 10;
}
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Get price
$price = $cart_item['data']->get_price();
// Set price
$cart_item['data']->set_price( $price + ( $price * $increaseby ) / 100 );
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
function action_wp_footer() {
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?>
<script type="text/javascript">
jQuery(function($){
$( 'form.checkout' ).on( 'change', 'input[name="payment_method"]', function() {
$(document.body).trigger( 'update_checkout' );
});
});
</script>
<?php
endif;
}
add_action( 'wp_footer', 'action_wp_footer' );
Related
I have a working script that adds a fee for certain products in an array.
But it only adds the fee for the first product in the array.
I have tried different options with my knowledge but it doesn't work. Any advice on what i'm doing wrong?
This is the code:
/* Add fee to specific product*/
add_action('woocommerce_cart_calculate_fees', 'statie_geld');
function statie_geld() {
if (is_admin() && !defined('DOING_AJAX')) {return;}
foreach( WC()->cart->get_cart() as $item_keys => $item ) {
$quantiy = $item['quantity']; //get quantity from cart
if( in_array( $item['product_id'], statiegeld_ids() )) {
WC()->cart->add_fee(__('Statiegeld Petfles 24'), 3.60 * $quantiy );
}
}
}
function statiegeld_ids() {
return array( 4535, 4537, 89694, 89706, 3223, 4742, 14846, 26972, 32925, 32927, 32929, 37475 );
}
Your code contains some mistakes
No need to use WC()->cart, $cart is passed to the function
$quantiy is overwritten on each loop
Same for adding the fee, this is overwritten on each loop
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
// Initialize
$quantity = 0;
// Loop though each cart item
foreach ( $cart->get_cart() as $cart_item ) {
// Compare
if ( in_array( $cart_item['product_id'], statiegeld_ids() ) ) {
// Addition
// Get product quantity in cart
$quantity += $cart_item['quantity'];
}
}
// Greater than
if ( $quantity > 0 ) {
// Add fee
$cart->add_fee( __( 'Statiegeld Petfles 24', 'woocommerce' ), 3.60 * $quantity );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
// Specify the product IDs
function statiegeld_ids() {
return array( 4535, 4537, 89694, 89706, 3223, 4742, 14846, 26972, 32925, 32927, 32929, 37475 );
}
I want to give customers with orders above $50 a free gift. Not if a specific product is in the cart (there are some examples here on stackoverflow and below).
After some research I found the following code to add a free product if another specific product is added to the cart.
add_action( 'template_redirect', 'bbloomer_add_gift_if_id_in_cart' );
function bbloomer_add_gift_if_id_in_cart() {
if ( is_admin() ) return;
if ( WC()->cart->is_empty() ) return;
$product_bought_id = 32;
$product_gifted_id = 57;
// see if product id in cart
$product_bought_cart_id = WC()->cart->generate_cart_id( $product_bought_id );
$product_bought_in_cart = WC()->cart->find_product_in_cart( $product_bought_cart_id );
// see if gift id in cart
$product_gifted_cart_id = WC()->cart->generate_cart_id( $product_gifted_id );
$product_gifted_in_cart = WC()->cart->find_product_in_cart( $product_gifted_cart_id );
// if not in cart remove gift, else add gift
if ( ! $product_bought_in_cart ) {
if ( $product_gifted_in_cart ) WC()->cart->remove_cart_item( $product_gifted_in_cart );
} else {
if ( ! $product_gifted_in_cart ) WC()->cart->add_to_cart( $product_gifted_id );
}
}
Found here: https://www.businessbloomer.com/woocommerce-buy-1-product-add-free-product-cart-programmatically/
I also tried this code but it doesn't update if the cart changes:
function aapc_add_product_to_cart() {
global $woocommerce;
$cart_total = 50;
if ( $woocommerce->cart->total >= $cart_total ) {
if ( ! is_admin() ) {
$free_product_id = 12989; // Product Id of the free product which will get added to cart
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $free_product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $free_product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $free_product_id );
}
}
}
}
add_action( 'template_redirect', 'aapc_add_product_to_cart' );
Is there any way to change that code to work with any product and limit only to the cart total?
Updated
With the following, a free gifted product will be added to cart if subtotal is up to a specific amount:
// Add free gifted product for specific cart subtotal
add_action( 'woocommerce_before_calculate_totals', 'check_free_gifted_product' );
function check_free_gifted_product( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Settings
$free_product_id = 37;
$targeted_subtotal = 50;
$cart_subtotal = 0; // Initializing
// Loop through cart items (first loop)
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ){
// When free product is is cart
if ( $free_product_id == $cart_item['product_id'] ) {
$free_key = $cart_item_key;
$free_qty = $cart_item['quantity'];
$cart_item['data']->set_price(0); // Optionally set the price to zero
} else {
$cart_subtotal += $cart_item['line_total'] + $cart_item['line_tax'];
}
}
// If subtotal match and free product is not already in cart, add it
if ( ! isset($free_key) && $cart_subtotal >= $targeted_subtotal ) {
$cart->add_to_cart( $free_product_id );
}
// If subtotal doesn't match and free product is already in cart, remove it
elseif ( isset($free_key) && $cart_subtotal < $targeted_subtotal ) {
$cart->remove_cart_item( $free_key );
}
// Keep free product quantity to 1.
elseif ( isset($free_qty) && $free_qty > 1 ) {
$cart->set_quantity( $free_key, 1 );
}
}
// Display free gifted product price to zero on minicart
add_filter( 'woocommerce_cart_item_price', 'change_minicart_free_gifted_item_price', 10, 3 );
function change_minicart_free_gifted_item_price( $price_html, $cart_item, $cart_item_key ) {
$free_product_id = 27;
if( $cart_item['product_id'] == $free_product_id ) {
return wc_price( 0 );
}
return $price_html;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
On cart page (the free gifted product is "Beanie"):
On mini cart:
I am trying to add a free product to the cart if the order total is above $199.99
I have achieved this and it is working. The issue is that I need to remove the product if the user then deletes an item from the cart and goes below $199.99 again (to prevent gaming the system).
What I have seems to be working. The problem is that it seems I need to click 2 links before the REMOVE FROM CART action seems to be working (or refresh the page).
What is causing this? Can the remove action be accomplished with AJAX by any chance?
// -------------------------------------------
// ADD PRODUCT IF ORDER MINIMUM ABOVE 200
/*
* Automatically adding the product to the cart when cart total amount reach to $199.99.
*/
function aapc_add_product_to_cart() {
global $woocommerce;
$cart_total = 199.99;
if ( $woocommerce->cart->total >= $cart_total ) {
if ( is_user_logged_in() ) {
$free_product_id = 339; // Product Id of the free product which will get added to cart
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $free_product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $free_product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $free_product_id );
}
}
}
if ( $woocommerce->cart->total <= $cart_total && $found ) {
WC()->cart->remove_cart_item( $free_product_id );
}
}
add_action( 'template_redirect', 'aapc_add_product_to_cart' );
add_action( 'template_redirect', 'remove_product_from_cart_programmatically' );
function remove_product_from_cart_programmatically() {
if ( is_admin() ) return;
$product_id = 339; // product id
$cart_total = 199.99;
$in_cart = false;
foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( $cart_item['product_id'] === $product_id ) {
$in_cart = true;
$key = $cart_item_key;
break;
}
}
if( WC()->cart->total < $cart_total ) {
if ( $in_cart ) WC()->cart->remove_cart_item( $key );
}
}
You should not use template_redirect hook to add or remove a free product based on a cart total threshold amount… Also your code is a bit outdated with some mistakes.
Instead use woocommerce_before_calculate_totals hook that is Ajax enabled, this way:
add_action( 'woocommerce_before_calculate_totals', 'add_or_remove_cart_items', 10, 1 );
function add_or_remove_cart_items( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// ONLY for logged users (and avoiding the hook repetition)
if ( ! is_user_logged_in() && did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$threshold_amount = 200; // The threshold amount for cart total
$free_product_id = 339; // ID of the free product
$cart_items_total = 0; // Initializing
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ){
// Check if the free product is in cart
if ( $cart_item['data']->get_id() == $free_product_id ) {
$free_item_key = $cart_item_key;
}
// Get cart subtotal incl. tax from items (with discounts if any)
$cart_items_total += $cart_item['line_total'] + $cart_item['line_tax'];
}
// If Cart total is up to the defined amount and if the free products is not in cart, we add it.
if ( $cart_items_total >= $threshold_amount && ! isset($free_item_key) ) {
$cart->add_to_cart( $free_product_id );
}
// If cart total is below the defined amount and free product is in cart, we remove it.
elseif ( $cart_items_total < $threshold_amount && isset($free_item_key) ) {
$cart->remove_cart_item( $free_item_key );
}
}
Code goes on functions.php file of your active child theme (or active theme). Tested and works.
Related: Other similar answer threads
We have some products in shop , and we are giving some coupons to customer .
product -> ABC price 10
coupon code is 'newcp' discount 20%;
so when people add the product to cart price will be 10 .
Then they apply coupon then original product price shown as 10 and calculate 20% from that and at the end the total will be 8
But now we need to change this as per specific condition
When people apply product coupon newbc
1)if coupon is newcp , then change order_item_price as order_item_price +3[ only if category is Fruit] , and this price should be shown in cart page, checkout page , order email
2)Calculate discount from the new price calculate discouunt from 13
3)If people remove coupon then price will again return to 10
I made 2 solutions , but not working.
Solution 1
add_action('woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price($cart_obj)
{
if (is_admin() && !defined('DOING_AJAX')) return;
foreach($cart_obj->get_cart() as $key => $value)
{
$product_id = $value['product_id'];
$coupon_code = $value['coupon_code'];
if ($coupon_code != '' && $coupon_code == "newcp")
{
global $woocommerce;
if (WC()->cart->has_discount($coupon_code)) return;
else
{
if (has_term('fruits', 'product_cat', $product_id))
{
$value['data']->set_price(CURRENT_CART_PRICE + 3);
}
}
}
}
}
Solution 2
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 ) {
$coupon = $code;
}
}
if ($coupon == "newcp"){
foreach ( $cart_object->get_cart() as $cart_item )
{
$price = $cart_item['data']->price+3;
$cart_item['data']->set_price( $price );
}
}
}
Please help .
Here is a possible way to achieve that:
// Add custom calculated price conditionally as custom data to cart items
add_filter( 'woocommerce_add_cart_item_data', 'custom_add_cart_item_data', 20, 2 );
function custom_add_cart_item_data( $cart_item_data, $product_id ){
// Your settings below
$product_categories = array('fruits');
$addition = 3;
$product = wc_get_product($product_id);
$the_id = $product->is_type('variation') ? $product->get_parent_id() : $product_id;
if ( has_term( $product_categories, 'product_cat', $the_id ) )
$cart_item['custom_price'] = $product->get_price() + $addition;
return $cart_item;
}
// Set conditionally a custom item price
add_action('woocommerce_before_calculate_totals', 'add_custom_price', 20, 1);
function add_custom_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Only for a DEFINED coupon code ( to be set below )
$coupon_code = 'newcp';
if ( ! $cart->has_discount( $coupon_code ) ) return;
foreach( $cart->get_cart() as $cart_item ) {
if ( isset($cart_item['custom_price']) ) {
$cart_item['data']->set_price( (float) $cart_item['custom_price'] );
}
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
I'm creating a WooCommerce add-on to customize the product, based on selected options by the visitor and custom price is calculated and stored into session table also.
I am able to get that value in cart page also.
My problem: I would like to change the default price of the product and replace it with new calculated value in the WooCommerce process as cart, checkout, payment, mail notifications, order...
Any advice please?
Thanks
Ce right hook to get it working is woocommerce_before_calculate_totals. But you will have to complete (replace) the code to get the new price in the hooked function below:
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_items_prices', 10, 1 );
function custom_cart_items_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 ) {
// Get the product id (or the variation id)
$product_id = $cart_item['data']->get_id();
// GET THE NEW PRICE (code to be replace by yours)
$new_price = 500; // <== Add your code HERE
// Updated cart item price
$cart_item['data']->set_price( $new_price );
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works on WooCommerce versions 3+. But as you don't give any code I can't test it for real getting the new price from session…
function save_subscription_wrap_data( $cart_item_data, $product_id ) {
$include_as_a_addon_subscription = get_field('include_as_a_addon_subscription',$product_id);
$subscricption_product_data = get_field('subscricption_product',$product_id);
$current_user = is_user_logged_in() ? wp_get_current_user() : null;
$subscriptions = wcs_get_users_subscriptions( $current_user->ID );
if($include_as_a_addon_subscription == "yes")
{
foreach ( $subscriptions as $subscription_id => $subscription ) {
$subscription_status = $subscription->get_status();
}
if($subscription_status == 'active')
{
$cart_item_data[ "subscribe_product" ] = "YES";
}
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'save_subscription_wrap_data', 99, 2 );
function render_meta_on_cart_and_checkout1( $cart_data, $cart_item = null ) {
$meta_items = array();
if( !empty( $cart_data ) ) {
$meta_items = $cart_data;
}
if( isset( $cart_item["subscribe_product"] ) ) {
$meta_items[] = array( "name" => "Product Type", "value" => "Package Addon" );
}
return $meta_items;
}
add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart_and_checkout1', 100, 2 );
function calculate_gift_wrap_fee( $cart_object ) {
if( !WC()->session->__isset( "reload_checkout" )) {
$additionalPrice = 100;
foreach ( WC()->cart->get_cart() as $key => $value ) {
if( isset( $value["subscribe_product"] ) ) {
if( method_exists( $value['data'], "set_price" ) ) {
$orgPrice = floatval( $value['data']->get_price() );
//$value['data']->set_price( $orgPrice + $additionalPrice );
$value['data']->set_price(0);
} else {
$orgPrice = floatval( $value['data']->price );
//$value['data']->price = ( $orgPrice + $additionalPrice );
$value['data']->price = (0);
}
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_gift_wrap_fee', 99 );