Set a custom calculated item price in Woocommerce mini-cart / Cart - php

Currently i have some custom calculation of product price based on different situation. When customer added a product in to cart then the custom price is set in session data , cart_item_data['my-price'] and i implemented using add_filter( 'woocommerce_add_cart_item') function and everything seems to working now .
Now the price in view cart page, checkout page is correct with my cart_item_data['my-price'].
But the only problem i am facing is the price is not updated in woocommerce mini cart that is appeared in the menu ,How can i change this ?
When i google i see a filter
add_filter('woocommerce_cart_item_price');
but i can't understand how to use this i do the following
add_filter('woocommerce_cart_item_price','modify_cart_product_price',10,3);
function modify_cart_product_price( $price, $cart_item, $cart_item_key){
if($cart_item['my-price']!==0){
$price =$cart_item['my-price'];
}
return $price;
//exit;
}
Here individual price is getting correct , but total price is wrong

Updated (october 2021)
For testing this successfully (and as I don't know how you make calculations), I have added a custom hidden field in product add to cart form with the following:
// The hidden product custom field
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
function add_gift_wrap_field() {
global $product;
// The fake calculated price
?>
<input type="hidden" id="my-price" name="my-price" value="115">
<?php
}
When product is added to cart, this my-price custom field is also submitted (posted). To set this value in cart object I use the following function:
add_filter( 'woocommerce_add_cart_item', 'custom_cart_item_prices', 20, 2 );
function custom_cart_item_prices( $cart_item_data, $cart_item_key ) {
// Get and set your price calculation
if( isset( $_POST['my-price'] ) ){
$cart_item_data['my-price'] = $_POST['my-price'];
// Every add to cart action is set as a unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
Now to apply (set) the new calculated price my-price to the cart item, I use this last function:
// For mini cart *(cart item displayed price)*
add_action( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 2 );
function filter_cart_item_price( $price, $cart_item ) {
if ( ! is_checkout() && isset($cart_item['my-price']) ) {
$args = array( 'price' => floatval( $cart_item['my-price'] ) );
if ( WC()->cart->display_prices_including_tax() ) {
$product_price = wc_get_price_including_tax( $cart_item['data'], $args );
} else {
$product_price = wc_get_price_excluding_tax( $cart_item['data'], $args );
}
return wc_price( $product_price );
}
return $price;
}
add_action( 'woocommerce_before_calculate_totals', 'set_calculated_cart_item_price', 20, 1 );
function set_calculated_cart_item_price( $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 ){
if( isset( $cart_item['my-price'] ) && ! empty( $cart_item['my-price'] ) || $cart_item['my-price'] != 0 ){
// Set the calculated item price (if there is one)
$cart_item['data']->set_price( $cart_item['my-price'] );
}
}
}
All code goes in function.php file of your active child theme (or active theme).
Tested and works

Related

Checkout price different from cart price using woocommerce_product_get_price hook

I´m running a WooCommerce (WordPress 6.1.1 and WooCommerce 7.3.0), and I´m trying to set prices according to the user role.
To do this I have introduced a new field named Webprice (precio_web) in product definition using the plugin: "Advanced Custom Fields". Customer users and not logged users must use this special price.
Also I added this code in my functions.php child-theme:
add_filter('woocommerce_product_get_price', 'ui_custom_price_role', 99, 2);
add_filter('woocommerce_product_get_regular_price', 'ui_custom_price_role', 99, 2);
add_filter('woocommerce_product_variation_get_regular_price', 'ui_custom_price_role', 99, 2);
add_filter('woocommerce_product_variation_get_price', 'ui_custom_price_role', 99, 2);
function ui_custom_price_role($price, $product) {
$price = ui_custom_price_handling($price, $product);
return $price;
}
Variable add_filter('woocommerce_variation_prices_price', 'ui_custom_variable_price', 99, 3);
add_filter('woocommerce_variation_prices_regular_price', 'ui_custom_variable_price', 99, 3);
function ui_custom_variable_price($price, $variation, $product) {
$price = ui_custom_price_handling($price, $product);
return $price;
function ui_custom_price_handling($price, $product) {
//get our current user
$current_user = wp_get_current_user();
//check if the user role is the role we want or is not logged
if ((!is_user_logged_in()) || (isset($current_user - \ > roles\[0\]) && '' != $current_user - \ > roles\[0\] && in_array('customer', $current_user - \ > roles))) { //load the custom price for our product $custom_price = get_post_meta( $product-\>get_id(), 'precio_web', true );
// custom price
if (!empty($custom_price)) {
$price = $custom_price;
}
}
return $price;
}
}
So far It works, when adding items to the cart I can see the new price.
enter image description here
The problem is at checkout for some reason prices displayed are the standard, not the ones corresponding to the new field.
enter image description here
Any help is welcome. Thanks.
I was expecting that the modification of the get_price function was enough because the prices are displayed correctly. However, the order is recorded with the standard price of the item.
WooCommerce recalculates all prices during the checkout process multiple times, so you need to hook into this recalculation also. This should work for you:
add_action( 'woocommerce_before_calculate_totals', 'update_cart_price'), 99);
function update_cart_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_item = $cart_item['data'];
$cart_item_product_id = $cart_item->get_id();
$product = wc_get_product( $cart_item_product_id );
$orig_price = $product->get_regular_price();
$new_price = ui_custom_price_handling( $orig_price, $product );
$cart_item->set_price( $new_price );
}
}

How to hide certain products on WooCommerce cart page

I have changed the main WooCommerce cart page using CSS to hide the products on this page.
The reason for the change, I am attempting to dedicate the cart page to only show the product "Thank You For The Tip" if it is in the cart, without changing any of the WooCommerce product settings to hidden.
All other products that have been added to the cart need to be hidden on the main WooCommerce cart page.
I see that I can not achieve this with CSS as the changes I made to the CSS will hide all products that have been added to the cart.
The closest I have come to finding a PHP solution is the following snippet:
add_filter( 'woocommerce_cart_item_visible', 'bbloomer_hide_hidden_product_from_cart' , 10, 3 );
add_filter( 'woocommerce_widget_cart_item_visible', 'bbloomer_hide_hidden_product_from_cart', 10, 3 );
add_filter( 'woocommerce_checkout_cart_item_visible', 'bbloomer_hide_hidden_product_from_cart', 10, 3 );
add_filter( 'woocommerce_order_item_visible', 'bbloomer_hide_hidden_product_from_order_woo333', 10, 2 );
function bbloomer_hide_hidden_product_from_cart( $visible, $cart_item, $cart_item_key ) {
$product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
if ( $product->get_catalog_visibility() == 'hidden' ) {
$visible = false;
}
return $visible;
}
function bbloomer_hide_hidden_product_from_order_woo333( $visible, $order_item ) {
$product = $order_item->get_product();
if ( $product->get_catalog_visibility() == 'hidden' ) {
$visible = false;
}
return $visible;
}
However, this does not give the desired result. Any advice?
To hide certain WooCommerce products only on the cart page and nowhere else, it suffices to just use the woocommerce_cart_item_visible filter hook.
In the $targeted_ids array you can indicate which productIDs should remain visible. This also works for variationIDs
function filter_woocommerce_cart_item_visible( $true, $cart_item, $cart_item_key ) {
// The targeted product ids
$targeted_ids = array( 30, 53 );
// Computes the intersection of arrays
if ( ! array_intersect( $targeted_ids, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) ) {
$true = false;
}
return $true;
}
add_filter( 'woocommerce_cart_item_visible', 'filter_woocommerce_cart_item_visible', 10, 3 );
To apply the reverse, and hide the productIDs that occur in the array
Replace
if ( ! array_intersect(..
With
if ( array_intersect(..

Auto add product to cart except for some WooCommerce product categories

I am using Auto add a product for cart item from specific product categories in WooCommerce answer code to auto add a free product to the cart. The code works great if the product is in a specific category but I need to add the product if it is NOT in a specific category.
I am able to add the free product if it is not in the specific category with this edit:
if( **!** has_term( $required_categories, 'product_cat', $item['product_id'] ) ) {
$matched_category = true;
}
But this does not remove the free product when the parent product is removed.
Any help would be appreciated!
Updated: Here are the changes that are required to "auto add a product in cart except for specific defined product categories (not removing the auto added product if mixed categories are in cart):
add_action( 'woocommerce_before_calculate_totals', 'auto_add_item_except_for_product_category', 10, 1 );
function auto_add_item_except_for_product_category( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Settings
$except_terms = array('t-shirts'); // Required product category(ies)
$auto_added_id = 70; // Specific product to be added automatically
$except_found = false;
$others_found = false;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Check for product category
if( has_term( $except_terms, 'product_cat', $cart_item['product_id'] ) ) {
$except_found = true;
} else {
$others_found = true;
}
// Check if specific product is already auto added
if( $cart_item['data']->get_id() == $auto_added_id ) {
$auto_added_item_key = $cart_item_key; // keep cart item key
}
}
// If auto added product is in cart with at least an item from a the defined product category only
if ( isset($auto_added_item_key) && $except_found && ! $others_found ) {
$cart->remove_cart_item( $auto_added_item_key ); // Remove specific product
}
// If there is at least an item from others product categories and the specific product is not in cart
elseif ( ! isset($auto_added_item_key) && ! $except_found ) {
$cart->add_to_cart( $auto_added_id ); // Add specific product
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Based on: Auto add a product for cart item from specific product categories in WooCommerce
Might be able to hook into the Woo's remove item from cart hook:
function remove_free_item() {
if ( is_admin() ) {
return;
}
$product_id = 'ID_OF_FREE_ITEM';
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$cart_item_key = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $cart_item_key ) {
WC()->cart->remove_cart_item( $cart_item_key );
}
}
add_action( 'woocommerce_cart_item_removed', 'after_remove_product_from_cart', 10, 2 );
function after_remove_product_from_cart($removed_cart_item_key, $cart) {
// removed item
$line_item = $cart->removed_cart_contents[ $removed_cart_item_key ];
// removed item product id
$product_id = $line_item[ 'product_id' ];
// might need to wrap this in some check depending on your case
remove_free_item();
}

WooCommerce - Show custom price in mini cart

I'm using the following code for dynamic pricing on WooCommerce products:
function add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
if( ! empty( $_POST['custom-total-price'] ) ) {
$product = wc_get_product( $product_id );
$price = $product->get_price();
$cart_item_data['custom_price'] = $_POST['custom-total-price'];
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_data', 10, 3 );
function before_calculate_totals( $cart_obj ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
foreach( $cart_obj->get_cart() as $key=>$value ) {
if( isset( $value['custom_price'] ) ) {
$price = $value['custom_price'];
$value['data']->set_price( ( $price ) );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'before_calculate_totals', 10, 1 );
The price is calculated with jQuery on the front end and sent through a form input when the product is added to the cart.
This is working in the sense that the cart total is updated, and the custom price for individual items is shown on the cart page. However, it's still showing a price of 0 in the mini cart. Any idea how I can show the custom price in the mini cart?
add_filter( 'woocommerce_cart_item_price', 'woocommerce_cart_item_price_filter', 10, 3 );
function woocommerce_cart_item_price_filter( $price, $cart_item, $cart_item_key ) {
/*
calculate price
*/
return $yourPrice;
}
I hope this helps you

Replace quantity field with a form if product is out of stock in Woocommerce

In woocommerce, using contact Form 7 plugin, I'm trying to replace the product quantity field, in the product summary, with a form, when a product is out of stock.
It works fine on variable products but on simple products it still shows the form and the quantity box.
It feels like I'm overlooking something very basic.
I've replaced the different echo with "simple" and "variable" to find out which form is shown, but on simple products it still shows the 'variable' form.
Here is my code:
add_action( 'woocommerce_single_product_summary', 'add_form' );
function add_form() {
global $product;
if( $product->is_type( 'simple' ) ){
// a simple product
if(!$product->is_in_stock( )) {
echo do_shortcode('[contact-form-7 id="304" title="Contact stock"]');
//echo "simple";
}
} elseif( $product->is_type( 'variable' ) ){
// a variable product
$count_in_stock == 0;
$variation_ids = $product->get_children(); // Get product variation IDs
foreach( $variation_ids as $variation_id ){
$variation = wc_get_product($variation_id);
if( $variation->is_in_stock() )
$count_in_stock++;
}
}
if( $count_in_stock == 0 ) {
echo do_shortcode('[contact-form-7 id="304" title="Contact stock"]');
//echo "variable";
}
}
Try the following code, that will replace quantity field and add to cart button with a form when the product is "out of stock" (for all product types, including variable products).
You say "on simple products it still shows the 'variable' form": It's because you are using the same shortcode on both simple and variable products. So you will need to add the correct different shortcode for simple products.
The code:
add_action( 'woocommerce_single_product_summary', 'action_single_product_summary_callback', 4 );
function action_single_product_summary_callback() {
global $product;
// Variable products
if ( $product->is_type( 'variable' ) ){
$count_in_stock = 0;
foreach ( $product->get_visible_children() as $variation_id ) {
$variation = wc_get_product($variation_id);
if( $variation->is_in_stock() ) {
$count_in_stock++;
}
}
if ( $count_in_stock === 0 ) {
// Remove quantity field and add to cart button
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
// Display the contact form
add_action( 'woocommerce_single_variation', 'display_variable_product_out_of_stock_form', 20 );
}
}
// Other products (Simple … )
else {
if ( ! $product->is_in_stock() ) {
// Remove quantity field and add to cart button
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
// Display the contact form
add_action( 'woocommerce_single_product_summary', 'display_simple_product_out_of_stock_form', 30 );
}
}
}
// Form for variable products
function display_variable_product_out_of_stock_form() {
echo do_shortcode('[contact-form-7 id="304" title="Contact stock"]');
}
// Form for Simple products
function display_simple_product_out_of_stock_form() {
echo do_shortcode('[contact-form-7 id="304" title="Contact stock"]'); // <== NOT the correct shortcode
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Categories