I have a plugin which applies discounts based on the category of the product. I'm using the filters below to add text to the order table in the cart:
add_filter('woocommerce_cart_product_subtotal', array($this,'change_product_subtotal'), 10, 4);
add_filter( 'woocommerce_cart_product_price', array($this,'change_product_price'), 10, 2);
add_filter( 'woocommerce_cart_item_name', array($this,'change_product_name'), 10, 2);
And this action to change the total price of the order/cart.
add_action( 'woocommerce_after_calculate_totals', array($this,'ca_change_cart_total'), 10, 1 );
The total price of the order pulls through to the checkout, as do the modified product fields. However when the order has been placed, the filters no longer have any effect (however the total order price is correct). My question is: what are the hooks I need to use to add the text present in the cart, to the placed order screen OR what is an alternative approach that will achieve the same outcome.I have provided screenshots showing the stages of the order. Thanks for any contributions.
For anyone having the same issue. I found an alternative method to using filters. Upon order creation loop through all the items in the order and change the totals. This has the advantage of effectively changing the unit price of the each product so in the WooCommerce admin area, if you are needing to issue a refund, the correct unit price is displayed. I have shown my code below, obviously replace 999 with the relevant total price for each product (ie unit price * quantity) using whatever custom logic your use case requires.
add_action('woocommerce_checkout_create_order', 'on_checkout_create_order', 20, 2);
function on_checkout_create_order( $order, $data ) {
foreach( $order->get_items() as $item_id => $line_item ){
$order->items[$item_id]->set_subtotal(999);
$order->items[$item_id]->set_total(999);
}
}
Related
I need to add in order metadata the amount of the discount for each product individually. For example, There are ten products in the order. The user has applied a coupon discount to the products. The total amount of the discount was calculated (if there are products on_sale, they were not taken into discount calculate).
But in the end, we got a total discount. And I need to split this discount for all the products that received it and even write this value into order item metadata.
Why don't I even have a sample code? I just don't know where to start. The only thing I think is to take the total discount, divide it by the number of products that can have a discount (these are all products in the order except on_sale), And add the resulting number to the product meta. But there is a problem, I'm not sure if this is the right solution. Could you please share any advice on how to solve this?
You can start with woocommerce_checkout_create_order_line_item action hook where you will be able to set custom order item meta data. This hook has 4 arguments:
$item the order item (object),
$cart_item_key the cart item key (string),
$values the cart item (array),
$order the order (object).
So you can get from the cart item $values the discounted line item totals using:
$line_discount = $value['line_subtotal'] - $value['line_total'];
$line_discount_tax = $value['line_subtotal_tax'] - $value['line_tax'];
Then for example all together to save the line discount total as custom order item meta data:
// Save Line item discount as custom order item meta data
add_action('woocommerce_checkout_create_order_line_item', 'action_checkout_create_order_line_item', 10, 4 );
function action_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
$line_discount = $value['line_subtotal'] - $value['line_total'];
$line_discount_tax = $value['line_subtotal_tax'] - $value['line_tax'];
$item->update_meta_data( '_line_discount', $line_discount + $line_discount_tax );
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Then you can get it from an order item object $item using the WC_Data method get_meta() like:
$line_discount = $item->get_meta('_line_discount');
Related: Get Order items and WC_Order_Item_Product in WooCommerce 3
I am trying to set a custom tax value for each product in Woocommerce which calculates as follows:
(price - cost) * (0,19/1,19)
Because Woocommerce doesn't offer a field for the cost of a product I installed the Cost of Goods - Woocommerce extension which allows to add this information to each product.
Then I went ahead to look for the function that calculates the taxes (calc_tax( $price, $rates, $price_includes_tax = false, $deprecated = false) and found the hook 'woocommerce_calc_tax' where I guess I have to hook into in order to change the calculated tax:
apply_filters(
'woocommerce_calc_tax',
$taxes,
$price,
$rates,
$price_includes_tax,
$suppress_rounding
);
In the file [includes/class-wc-tax.php][2].
But since the hook offers only five parameter - none of which represents costs of a product. I have no idea how to pass the cost of a product to a function that hooks into this hook.
So my question is, how to pass the cost of a product (from Cost of Goods plugin) to this hook to use in a custom calculation of tax as described above.
Or is there a different way to do this?
I am using woocommerce subscription with the gifting extension. With this it is possible to gift a subscription to a recipient. I am trying to make it possible to gift a subscription to multiple people in one order.
The tricky thing is that each product by default can only be gifted to 1 person. So in order to gift to multiple people, the same product has to be added to the cart multiple times.
With the use of this thread: WooCommerce - Treat cart items separate if quantity is more than 1
I have managed to add the same product to the cart and show in on multiple lines. So if I enter quantity 5 of my subscription product and add it to the cart I get five entries in my cart. Which is great, as now I can gift every line to another person.
However, when I proceed to checkout it gets messed up again. Instead of showing the product on separate lines, everything get jammed together. Thus on checkout I get to see 1 line with quantity 5, instead of 5 lines with quantity 1.
This is where the question comes in:
How can I make sure that the order review table on the checkout page shows separate lines for a product with quantity x>1 instead of 1 line with quantity x?
Remark:
I figured out that it only does not work when the woocommerce subscription gifting add-on is active. It overrides seem to override the wc_cart_item_data
you can use this code
function separate_individual_cart_items( $cart_item_data, $product_id ) {
$unique_cart_item_key = md5( microtime() . rand() );
$cart_item_data['unique_key'] = $unique_cart_item_key;
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'separate_individual_cart_items', 10, 2 );
you can put this code into functions.php or into yout own plugin ( a best solution).
And a observation because this question is similar like this question
WooCommerce - Treat cart items separate if quantity is more than 1
but I can't close the question, sorry... my reputation is low)
I am currently developing a webshop where i needed to do a separate price function. So far, with the help of woocommerce hooks, i had managed to manipulate the price in both the shopping cart and the checkout, this works without any problems at all. Hooks i have used woocommerce_cart_item_price, woocommerce_cart_item_subtotals, woocommerce_cart_subtotal and woocommerce_cart_total.
Now we come to my problem that i need to solve in the very near future. The price from my custom function is not included in the woocommerce order. So, is there a hook to manipulate the product prices in the order before the woocommerce creates the order?
I have looked at https://docs.woocommerce.com/wc-apidocs/hook-docs.html
but with no success.
Where does Woocommerce get the price from when it creates the order? The _price meta field, woocommerce_get_price hook, the cart or something else. I would be very grateful if someone could explain this to me. I find that woocommerce is not very consistent with where it's getting the price from.
Please ask questions if you don't understand my problem or my relative poor English. Thanks in advance.
I've use the woocommerce_get_price hook, when you change it, that changed price will be used for the cart to calculate the total (price * qty).
After order is placed, WooCommerce calculates the product based price on the total and qty, if you change one of the 2 values (total or qty) it will change the product price.
In other words, the price is dynamic after order has been created.
Edit:
Added method to change price
function change_price( $cart ) {
// Exit function if price is changed at backend
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
foreach ( $cart->get_cart() as $key => $item ) {
$item['data']->set_price( $custom_price );
}
}
add_action( 'woocommerce_before_calculate_totals', 'change_price', 10, 1);
I've got a customized WooCommerce shop where I want to be able to grey out certain product variations based on conditions, but I'm not sure where in the code to do it.
I have two prices for each item, one is a member price and one is a retail price.
I want everyone to see each variation but not be able to select the one that isn't available to them, so that non-members can see the retail price but can't select it, and vice versa.
The other customization I want is the following: I want to be able to only allow members to buy 5 products at member price per month, and then it will switch them over to retail price, so I need to be able to grey out the member price for members based on certain conditions as well.
Can anyone point me to the files/hooks/actions where I can inject some custom code into the variation output so I can make this happen?
Thanks.
For your two questions you can use in a different way woocommerce_add_to_cart_validation filter hook. With some conditions based on your users roles and on existing function arguments, customer will be able to select a variation of your product, but will not be able to added it to cart, if he is not allowed. You can even display a notice when customer try to add something when is not allowed…
add_filter( 'woocommerce_add_to_cart_validation', 'custom_add_to_cart_validation', 10, 5 );
function custom_add_to_cart_validation( $passed, $product_id, $quantity, $variation_id, $variations ) {
// Your code goes here
// If $passed is set to "false", the product is not added
// $passed = false;
return $passed;
}
For your last question, you will need to set/update some custom user meta data regarding the 5 products by month for the members, each time they place an order. You can use for this the woocommerce_thankyou or woocommerce_order_status_completed action hooks to set that custom data in the user meta data. Then you will be able to check this data enabling or disabling the right product variation in the woocommerce_add_to_cart_validation filter hook.
To finish, if you really want to grey out some variations, you will have to use Javascript/jQuery, but is going to be quite difficult as there is already a lot of javascript/Ajax WooCommerce events on product variations, that will conflict yours. But in WooCommerce everything is possible depending on time and skills…