I'm trying to set the free trial period of a cart item in WooCommerce during an add to cart AJAX request. The code seems to work when there is one subscription product in the cart, but when there are two or more of the same subscription product in the cart, the free trial is applied to all those products as well, even though the code is only specifically altering the cart data for one of the products. The code I'm using is below. Also $job->get_free_trial_length() is definitely returning the correct value. Any help would be greatly appreciated as I've been struggling with this for some time! Thanks.
UPDATE
When changing the free trial period on the cart item, it seems to also updates the subscription product's free trial period, which is why the other products also changed. So my question is, can free trials be done on a cart item level instead of a product level?
/**
* Add the subscription package to the user's cart.
*
* #param int $job_id
* #param int $variation_id
* #return string
*/
function add_package_to_cart( $job_id, $variation_id ) {
$job = fcrm_get_job( $job_id );
$product_id = $job->get_linked_subscription_product_id();
$quantity = 1;
$cart_item_data = array(
'job_id' => $job_id
);
// Add to cart
$key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, array(), $cart_item_data );
// Set the free trial period
wcs_set_objects_property( WC()->cart->cart_contents[ $key ]['data'], 'subscription_trial_length', $job->get_free_trial_length() );
return $key;
}
Found the solution. wcs_set_objects_property() accepts a 4th argument to not save the value to the database, but instead keep the value in memory. Then call the function every time cart totals are calculated.
Related
I created a custom product type for WooCommerce. With this product type it is possible to connect an other product that is exist by ID.
WooCommerce reduce the stock quantity automatically if an order is placed and the payment is successful.
For example I added a product with ID 4082 to the cart with a quantity from 3.
After place this order WooCommerce updated the stock from product 4082 with -3.
Ok back to my custom product type. As I said it is possible to connect another product by ID.
For example I connect product 4082 with product ID 10988.
If a customer add product 4082 to the cart and placed the order I want reduce the stock quantity from product ID 10988 and not from 4082.
<?php
add_action('woocommerce_checkout_order_processed', 'stocktest');
function stocktest($order_id){
$order = wc_get_order( $order_id );
$order_item = $order->get_items();
foreach( $order_item as $product ) {
//for the topic I programmed the IDs hardcoded
if($product->ID == '4082'){
wc_update_product_stock( 10998, $product['qty'], 'decrease', '' );
}
}
}
?>
I tried the code above and the stock from ID 10998 is correctly decreased but also the stock from ID 4082 is decreased.
Do I use the wrong hook? And how can I make the function correctly?
Hope somebody can help me with this.
Thanks a lot
Does wc_update_product_stock( 4082, $product['qty'], 'increase', '' ); not work?
That way, the stock should be adjusted for the 4082 product.
Also, there might be a potential issue with your snippet. The $product variable refers to the product object of 4082 product, not the 10998 product.
Maybe try something like this?
<?php
add_action('woocommerce_checkout_order_processed', 'stocktest');
function stocktest($order_id){
$order = wc_get_order( $order_id );
$order_item = $order->get_items();
foreach( $order_item as $product ) {
//for the topic I programmed the IDs hardcoded
if($product->ID == '4082'){
$connected_qty = get_post_meta( 10988, '_stock', true );
wc_update_product_stock( 10998, $connected_qty, 'decrease', '' );
wc_update_product_stock( 4082, $product['qty'], 'increase', '' );
}
}
}
?>
Instead of using the custom field query, you could use the WC_Product class:
$connected_product = wc_get_product(10998);
$connected_qty = $connected_product->get_stock_quantity();
I did some research on your question. WooCommerce called a lot of functions to update the stock af order / payment. If an order is placed the items become an status reduce_stock yes or no.
If is yes go further and update the stock of this item. After this WooCommerce created the e-mails and ordernotes.
All this functions worked together please be careful with changing the code in the file wc-stock-functions.php
If you want change and try something do this for example on a local testserver.
This are some functions in the file
<?php
wc_maybe_reduce_stock_levels();
wc_maybe_increase_stock_levels();
wc_reduce_stock_levels();
wc_trigger_stock_change_notifications();
?>
I am developing a Woocommerce shop and want to offer all members (users logged in) 20% off their Total.
I have created a coupon called "twentypercent_off" and I am programmatically applying this using a custom function and a hook in my functions.php.
This works well.
In WC settings I have checked "Calculate coupon discounts sequentially" and this works almost as I would expect.
However what I would like is that my "twentypercent_off" is always applied last in cases where there are multiple coupons.
No matter what I have attempted to do (loop through all coupons on current order, remove all coupons, add them back in the order I desire) I find that Woo-commerce seems to always apply them in the order of monetary savings.
For example if the customer orders $100 worth of products and they have a coupon for $25 and also qualified to receive 20% off total.
I would like the total to calculate as (100 -25) * 0.8 = $60
but WC is calculating as such (100 * 0.8) - 25 = $55
I tried the following but it made no difference:
if ( is_user_logged_in() ) {
$Coupon_code = 'twentypercent_off';
$Current_Coupons = WC()->cart->get_coupons();
$Non_Prog_Coupons=array();
// loop through all current coupons
foreach( $Current_Coupons as $code => $coupon ){
if($code==$coupon_code){
WC()->cart->remove_coupon( $code );
} else {
WC()->cart->remove_coupon( $code );
$Non_Prog_Coupons[]=$code; // array of non-programmatically added coupons
}
}
// loop through non-programmatically added coupons
foreach( $Non_Prog_Coupons as $x => $code ){
WC()->cart->add_discount( $code ); // add them again
}
// add programmatically added coupon last !
WC()->cart->add_discount($Coupon_code);
}
return;
The only possible solution I have come across is to apply the 20% discount as a negative fee, which is not suitable for our purposes and would be an absolute last resort
Any ideas on how to achieve this would be greatly appreciated
I need to update the order item meta in a woocommerce oder on checkout page or while woocommerce creates the order.
I'm using the plugin visual product configurator and it is not passing the right quantity of some items of the order to woocommerce order meta, especially when I use multiple variations on the same product.
Is there a hook for me to use to update the item quantity for a certain order item and how can I use it?
The plugin returns me an array with all the cart information and I can only check if an item of the order appears multiple times - if yes I need to change the quantity of that item to that number in the woocommerce order/database.
I was thinking of adding the following hook to my functions.php
add_action('woocommerce_checkout_create_order', 'change_qty', 1,1);
function change_qty($item_qty){
foreach($item_qty as $qty) {
$qty['product_id'] = $id;
$qty['qty'] = $new_qty
$order->update_meta_data('quantity', $new_qty, $id)
}
}
Whereas $item_qty is be an multi-dimensional array containing the item_ids and adjusted quantities.
Another problem I'm facing is that I dont know when I need to call that function because I get the array from the plugin on the checkout page, but I think WooCommerce has not yet created an order at that moment?
The result should be an adjusted item quantity in the woocommerce order summary in the backend.
To update the order item quantity, you can use WC_Order_Item_Product set_quantity() method.
The correct hook to update order items (line items) is woocommerce_checkout_create_order_line_item action hook, that is triggered during order creation, before data is saved to databased.
add_action('woocommerce_checkout_create_order_line_item', 'change_order_line_item_quantity', 10, 4 );
function change_order_line_item_quantity( $item, $cart_item_key, $cart_item, $order ) {
// Your code goes below
// Get order item quantity
$quantity = $item->get_quantity();
$new_qty = $quantity + 2;
// Update order item quantity
$item->set_quantity( $new_qty );
}
The function arguments (variables) are defined and usable:
$item is the WC_Order_Item_Product Object (not saved yet to database)
$cart_item_key is the related cart item key
$cart_item is the related cart item data
$order is the WC_Order Object (not saved yet to database)
Related:
Get Order items and WC_Order_Item_Product in Woocommerce 3
WC_Order_Item_Product Class and methods API Documentation
WC_Checkout and woocommerce_checkout_create_order_line_item action hook located in the create_order_line_items() method
This can help you (we hook into payment completed notification from the payment provider). If you want to update the _qty just after the order was created, I can change my function. But for now I would update it only when the payment was successful.:
/**
* Update order item qty after payment successful
*/
add_filter( 'woocommerce_payment_complete_order_status', 'update_order_item_qty', 10, 2 );
function update_order_item_qty( $order_status, $order_id ) {
//Get the order and items
$order = new WC_Order( $order_id );
$items = $order->get_items();
//New qty
$new_qty = 0;
foreach ( $items as $item_id => $item_data ) {
update_meta_data( '_qty', $new_qty, $item_id );
}
}
Please try if this is what you'r looking for.
I need to change the item price in a woocommerce order but everything I found is to changing the price in the cart but this is not what I need because I need to change after the checkout process.
Does somebody can give me a clue on how to do that?
You need to use the new CRUD setters methods introduced with Woocommerce 3:
For order object you will use WC_Order methods,
For order "line item" you will use WC_Order_Item_Product methods,
For both of them you could be also use some WC_Data methods like save()…
Here is a working basic example with a static price and a static order ID:
$order_id = 809; // Static order Id (can be removed to get a dynamic order ID from $order_id variable)
$order = wc_get_order( $order_id ); // The WC_Order object instance
// Loop through Order items ("line_item" type)
foreach( $order->get_items() as $item_id => $item ){
$new_product_price = 50; // A static replacement product price
$product_quantity = (int) $item->get_quantity(); // product Quantity
// The new line item price
$new_line_item_price = $new_product_price * $product_quantity;
// Set the new price
$item->set_subtotal( $new_line_item_price );
$item->set_total( $new_line_item_price );
// Make new taxes calculations
$item->calculate_taxes();
$item->save(); // Save line item data
}
// Make the calculations for the order and SAVE
$order->calculate_totals();
Then you will have to replace the static price by your submitted new price in your custom page, which is not so simple, as you will need to target the correct $item_id…
Thank you very much, I spent 4 hours looking for how to change the quantity of the product in the order and based on your code (I rewrote the necessary part) I finally got it! that's if someone needs to change the quantity product in the order `
$order = wc_get_order( $_POST['orderID'] );
foreach( $order->get_items() as $item_id => $item ){
$product = $item->get_product();
$product_price = (int) $product->get_price(); // A static replacement product price
$new_quantity = (int) $_POST['productQty'] // product Quantity
// The new line item price
$new_line_item_price = $product_price * $new_quantity;
// Set the new price
$item->set_quantity($_POST['orderQty']);
$item->set_subtotal( $new_line_item_price );
$item->set_total( $new_line_item_price );
// Make new taxes calculations
$item->calculate_taxes();
$item->save(); // Save line item data
}
// Make the calculations for the order and SAVE
$order->calculate_totals();`
#LoicTheAztec
Completing an automated woo-commerce Payment by manually inputting an identifier
The shopper goes online, creates an account , adds a payment method, and fills their cart .
We hold the amount plus 15% when they check out.
woocommerce sends order details to the delivery team that takes the gig .
They go to the store and shop
After checking out at the physical store, the new invoice total is uploaded to woo-commerce via the shopping app .
This manually entered amount will be the IDENTIFIER in the stripe that TRIGGERS the order completion
I'm developing a plugin that creates an order directly (no cart) and applies a coupon. In version 3.0 of the woo API the function add_coupon() has been deprecated in favour of a WC_Order_Item_Coupon object you add to the order.
Create the coupon
$coupon = new WC_Order_Item_Coupon();
$coupon->set_props(array('code' => $coupon, 'discount' => $discount_total,
'discount_tax' => 0));
$coupon->save();
This is successful. I can validate by calling $coupon->get_discount().
I then add the coupon to the order and recalculate totals:
$order->add_item($item);
$order->calculate_totals($discount_total);
$order->save();
Logging into wp-admin I can see the order with coupon code visible. However, the coupon has had no effect on line items or total.
Have a misunderstood how api v3.0 intends us to handle coupons?
How about using WC_Abstract_Order::apply_coupon?
/**
* Apply a coupon to the order and recalculate totals.
*
* #since 3.2.0
* #param string|WC_Coupon $raw_coupon Coupon code or object.
* #return true|WP_Error True if applied, error if not.
*/
public function apply_coupon( $raw_coupon )
Here is my code.
$user = wp_get_current_user();
$order = new WC_Order();
$order->set_status('completed');
$order->set_customer_id($user->ID);
$order->add_product($product , 1); // This is an existing SIMPLE product
$order->set_currency( get_woocommerce_currency() );
$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
$order->set_customer_user_agent( wc_get_user_agent() );
$order->set_address([
'first_name' => $user->first_name,
'email' => $user->user_email,
], 'billing' );
// $order->calculate_totals(); // You don't need this
$order->apply_coupon($coupon_code);
$order->save();
OK, so I played about a little longer and it looks like in V3 things are a little more manual.
Adding a WC_Order_Item_Coupon item to a woo order does simply that. It adds the coupon object to the order object. No calculations are made and the product line items remain unchanged. You have to iterate over the product items manually and apply the coupon yourself by calculating the line item totals and subtotals. calculate_totals() then does as expected.
// Create the coupon
global $woocommerce;
$coupon = new WC_Coupon($coupon_code);
// Get the coupon discount amount (My coupon is a fixed value off)
$discount_total = $coupon->get_amount();
// Loop through products and apply the coupon discount
foreach($order->get_items() as $order_item){
$product_id = $order_item->get_product_id();
if($this->coupon_applies_to_product($coupon, $product_id)){
$total = $order_item->get_total();
$order_item->set_subtotal($total);
$order_item->set_total($total - $discount_total);
$order_item->save();
}
}
$order->save();
I wrote a helper function to make sure the coupon applies to the product in question coupon_applies_to_product(). Strictly not needed given I'm creating the order entirely in code.. but I use it it other places so added it.
// Add the coupon to the order
$item = new WC_Order_Item_Coupon();
$item->set_props(array('code' => $coupon_code, 'discount' => $discount_total, 'discount_tax' => 0));
$order->add_item($item);
$order->save();
You now get the nicely formatted order in wp-admin with line items showing the specific discount + the coupon code etc.