Price in the shopping cart [duplicate] - wordpress

I am trying to change product price in cart using the following function:
add_action( 'woocommerce_before_shipping_calculator', 'add_custom_price'
);
function add_custom_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->price = 400;
}
}
It was working correctly in WooCommerce version 2.6.x but not working anymore in version 3.0+
How can I make it work in WooCommerce Version 3.0+?
Thanks.

Update 2021 (Handling mini cart custom item price)
With WooCommerce version 3.0+ you need:
To use woocommerce_before_calculate_totals hook instead.
To use WC_Cart get_cart() method instead
To use WC_product set_price() method instead
Here is the code:
// Set custom cart item price
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 1000, 1);
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 ) {
$cart_item['data']->set_price( 40 );
}
}
And for mini cart (update):
// Mini cart: Display custom price
add_filter( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 3 );
function filter_cart_item_price( $price_html, $cart_item, $cart_item_key ) {
if( isset( $cart_item['custom_price'] ) ) {
$args = array( 'price' => 40 );
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_html;
}
Code goes in functions.php file of your active child theme (or active theme).
This code is tested and works (still works on WooCommerce 5.1.x).
Note: you can increase the hook priority from 20 to 1000 (or even 2000) when using some few specific plugins or others customizations.
Related:
Set cart item price from a hidden input field custom price in Woocommerce 3
Change cart item prices based on custom cart item data in Woocommerce
Set a specific product price conditionally on Woocommerce single product page & cart
Add a select field that will change price in Woocommerce simple products

With WooCommerce version 3.2.6, #LoicTheAztec's answer works for me if I increase the priority to 1000.
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 1000, 1);
I tried priority values of 10,99 and 999 but the price and total in my cart did not change (even though I was able to confirm with get_price() that set_price() had actually set the price of the item.
I have a custom hook that adds a fee to my cart and I'm using a 3rd party plugin that adds product attributes. I suspect that these WooCommerce "add-ons" introduce delays that require me to delay my custom action.

Related

Can't pass custom cart item data to WC()->cart->add_to_cart() woocommerce 4.9

I'm working on woocommerce API plugin development and trying to pass custom cart item data using the below code in add to cart API endpoint.
$cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations, array('margin' => 200));
and want to use that custom cart item data on woocommerce_before_calculate_totals hook (see code below) but can't getting custom cart item data ($cart_item['margin']) there.
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_item_price', 30, 1 );
function custom_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
foreach ( $cart->get_cart() as $cart_item ) {
if( isset($cart_item['margin']) ){
$final_price = ($cart_item['data']->get_price() + $cart_item['margin']);
$cart_item['data']->set_price($final_price);
}
}
}
I have installed Woocommerece 4.9 version, please help me to solve this issue.
Thanks in advance.
I had kind of the same problem, the issue was there was another plugin that might have a higher priority on the filter. It was a Role based pricing plugin, after deactivating it, everything worked. So just check if there is no other thing overwriting the function.
To do a test I used the woocommerce_add_to_cart_validation hook and I added a product to cart with add_to_cart() method of the WC_Cart class.
add_action( 'woocommerce_add_to_cart_validation', 'add_product_to_cart_programmatically', 10, 3 );
function add_product_to_cart_programmatically( $passed, $product_id, $quantity) {
$product_id = 166; // product id to add
$quantity = 10; // quantity product to add
WC()->cart->add_to_cart( $product_id, $quantity, 0, array(), array( 'margin' => 200 ) );
return $passed;
}
Once the product has been added to the cart, I can apply a custom price based on the custom cart item data:
add_action( 'woocommerce_before_calculate_totals', 'custom_cart_item_price', 30, 1 );
function custom_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
foreach ( $cart->get_cart() as $cart_item ) {
if ( isset( $cart_item['margin'] ) && ! empty( $cart_item['margin'] ) ) {
$final_price = $cart_item['data']->get_price() + $cart_item['margin'];
$cart_item['data']->set_price( $final_price );
}
}
}
As recommended by #danielsalare you can try to increase the priority of the action, as in my example above.
I had a similar problem and found this solution: First, we add the custom products to Woocommerce. Second, we generate an identifier (ID), and later we add it.
for example, obtain product-id trow a with $_POST
$myProduct = $_POST['myProduct'];
$myProduct_id = WC()->cart->generate_cart_id($myProduct);
if (!WC()->cart->find_product_in_cart($myProduct_id )) {
WC()->cart->add_to_cart($myProduct);
}

WooCommerce Multivendor Marketplace get vendor id from product id

I am using WooCommerce Multivendor Marketplace plugin in Wordpress for multivendor site. I want to restrict a user so they can add only one vendor's product in their cart. I am writing a custom function to get vendor id.
I'm trying to use the get_wcfm_product_vendors function but it isn't working; I think that it might not be supported. I've search for other possible solutions but I could not find any. Is there any other method I can use to get vendor id for a product?
You may try WCFM single vendor checkout function, add this code to your child theme :
add_action( 'woocommerce_add_to_cart_validation', function( $is_allow, $product_id, $quantity ) {
$product = get_post( $product_id );
$product_author = $product->post_author;
//Iterating through each cart item
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_product_id = $cart_item['product_id'];
$cart_product = get_post( $cart_product_id );
$cart_product_author = $cart_product->post_author;
if( $cart_product_author != $product_author ) {
$is_allow = false;
break;
}
}
if( !$is_allow ){
// We display an error message
wc_clear_notices();
wc_add_notice( __( "Well, you already have some item in your cart. First checkout with those and then purchase other items!", "wcfm" ), 'error' );
}
return $is_allow;
}, 50, 3 );
https://docs.wclovers.com/tweaks/#single-vendor-checkout

Hide shipping and payment methods in WooCommerce

I'm building a WooCommerce e-shop and I need to tweak my checkout page by doing the following:
Hide a certain shipping method (only one) if the order total > 100€.
Hide the cash on delivery payment method if local pickup is selected.
Does anyone know how to do that? I have the Code Snippets plugin so I can easily add any custom code.
To hide specific shipping method based on the cart total, you can use below code snippet. You need to update your shipping method name in the code.
Disable shipping method as per cart total
Add this snippet in your theme's functions.php file or custom plugin file.
add_filter( 'woocommerce_package_rates', 'shipping_based_on_price', 10, 2 );
function shipping_based_on_price( $rates, $package ) {
$total = WC()->cart->cart_contents_total;
//echo $total;
if ( $total > 100 ) {
unset( $rates['local_delivery'] ); // Unset your shipping method
}
return $rates;
}
Disable Payment Gateway For Specific Shipping Method
Use below code snippet. Update code as per your payment method & shipping method.
add_filter( 'woocommerce_available_payment_gateways', 'x34fg_gateway_disable_shipping' );
function x34fg_gateway_disable_shipping( $available_gateways ) {
global $woocommerce;
if ( !is_admin() ) {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
$chosen_shipping = $chosen_methods[0];
if ( isset( $available_gateways['cod'] ) && 0 === strpos( $chosen_shipping, 'local_pickup' ) ) {
unset( $available_gateways['cod'] );
}
}
return $available_gateways;
}
There are a number of plugins that will do this for you, take a look at this one WooCommerce Conditional Shipping and Payments
You'll want to tie in to the "woocommerce_payment_gateways" action
Something along these lines:
function alter_payment_gateways( $gateways ){
$chosen_rates = ( isset( WC()->session ) ) ? WC()->session->get( 'chosen_shipping_methods' ) : array();
if( in_array( 'local-pickup:6', $chosen_rates ) ) {
$array_diff = array('cod');
$list = array_diff( $list, $array_diff );
}
return $list;
}
add_action('woocommerce_payment_gateways', 'alter_payment_gateways', 50, 1);
The number on the end of 'local-pickup' on line 4 will depend on your woocommerce setup. You can find the string you need to put in here by adding something to a basket, going to the checkout, right clicking on the "Local Pickup" option in the delivery methods and looking at the value attribute.

Woocommerce Applying Coupon on Specific product in Cart

I want to apply the discount coupon to the specific product in cart from checkout page.
Inside the cart:
product1 w/ upgrades
product2 w/o upgrades
when I apply the discount coupon I want that the discount will take effect only in product2's price. I tried to search in some forums but the coupon will take effect in the whole cart items.
You can try this piece of code:
function calculate_variation_addon_price( $cart_object ) {
global $isProcessed;
// Loop for all products in cart
foreach ( $cart_object->cart_contents as $key => $value ) {
// Your condition here for product specific i.e. id == 25
if((!isset($isProcessed) || empty($isProcessed))) {
$orgPrice = floatval( $value['data']->get_price() );
$cart_object->cart_contents[$key]['data']->set_price( $orgPrice * 0.5 );
}
}
$isProcessed = 1;
}
add_action( 'woocommerce_before_calculate_totals', 'calculate_variation_addon_price', 2, 1 );
While adding coupon from admin panel, find a tab there, called 'Usage Restriction'.
There you can add products or product categories or even exclude some for the coupon code to be applied.
You can so that using product id, sku or name
function filter_woocommerce_coupon_get_discount_amount( $discounting_amount, $price_to_discount , $cart_item, $single, $coupon ) {
// On backorder
if ( $cart_item['data']->get_id() !== 'product2_id' ) {
$discounting_amount = 0;
}
return $discounting_amount;
}
add_filter( 'woocommerce_coupon_get_discount_amount', 'filter_woocommerce_coupon_get_discount_amount', 10, 5 );
You can use in_array instead of !== for multiple products
You also replace get_id() by other properties or use custom attributs...

Wordpress variable, user created, woocommerce product

Basically I am interested in using woocommerce to sell a product . This product is a Print Order of a external printing service that I have implemented in a brand new plugin.
What I want now is after the order, is to be able to put that "order" in the buy cart, and buy it normally as just another woocommerce product.
The product has to be created on the fly, manually by a way of some function that I can use to create a product during a certain workflow point.
Can you help me to find a solution?
Using woocommerce or not!
What i understand from your requirement/comments is that you want to be able to dynamically create a product, which is bad idea. But here is my suggestion.
Lets say you have a simple product called "Print Job" with a price of $1 and with an id of 10. And i am supposing that your external printing service would send back a response with the order and the price of printing, lets say $64.
Once you recieve the response you can simply call add_product_to_cart(10), this will automatically add the print job product to your cart.
/************* functions.php ***************/
function add_product_to_cart($product_id) {
if ( ! is_admin() ) {
$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->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
You also need to add this function in your functions.php, this function will override the price of the product i.e "Print Job" with the actual price of $64.
/******************* Functions.php ****************/
add_action( 'woocommerce_before_calculate_totals', 'override_printing_price' );
function override_printing_price( $cart_object ) {
$custom_price = 64;
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->price = $custom_price;
}
}

Resources