We had a legacy system that used Woocommerce but not Woocommerce Subscriptions, we've since migrated to Woocommerce Subscriptions but we have a tonne of standard Woo orders that we'd like to tie to subscriptions.
Via the database, if I find the subscription in the postmeta table, I can manually change _subscription_renewal_order_ids_cache to include the order id so it becomes the following:
a:2:{
i:0;i:143052;
i:1;i:143049;
}
(I've added the second line)
On the order itself if I add the meta _subscription_renewal with the subscription id that then ties the order to the subscription.
Can this be done programmatically? I've done the following but it's not outputting the meta (so therefore I can't amend it).
global $wpdb;
// get all subscriptions IDS
$subscriptions_ids = $wpdb->get_col("
SELECT ID FROM {$wpdb->prefix}posts
WHERE post_type LIKE 'shop_subscription'
");
// Loop through subscriptions Ids
foreach( $subscriptions_ids as $subscription ){
// Get an instance of the WC_Subscription object
$subscription = new WC_Subscription( $subscription );
$subscription_id = $subscription->get_id();
$subscription_email = $subscription->get_billing_email();
echo $subscription->get_meta('_subscription_renewal_order_ids_cache');
echo "<pre>";
print_r( $subscription );
echo "</pre>";
}
I've not gone any further with the code until I'm able to output and amend the post meta.
This can be done by going through orders and adding the meta line:
$order = wc_get_order();
$order->update_meta_data( '_subscription_renewal', $subscription_id );
$order->save();
With $subscription_id being the ID of the subscription you'd like to tie the order to.
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 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 am using Woocommerce with Woocommerce Booking plugin and I would like to update the order status to refunded every time a paid booking is cancelled.
I've found some answers on StackOverFlow, but still can't manage to solve this requirement.
I know I might be completely wrong, but this the last try I made and obviously it didn't work:
add_action('woocommerce_booking_paid_to_cancelled','change_status_to_refund', 10, 2);
function change_status_to_refund($booking_id, $order_id) {
$booking = new WC_Order($booking_id);
$order = new WC_Order($order_id);
$booking_status = $booking->get_status();
if($booking_status != 'paid'){
$order->update_status('refund', 'order_note');
}
}
Any help is welcome.
You are not using the correct arguments for woocommerce_booking_{ status_from }_to_{ status_to } action hook in your function, which are:
The booking ID: $booking_id,
The Booking Object $booking.
So you need to get the Order from the Booking in your code, to be able to update the Order status.
Note: The condition $booking_status != 'paid' is not really needed.
So your code will be much simpler and effective:
add_action('woocommerce_booking_paid_to_cancelled','cancelled_booking_order_status_cahnged_to_refund', 10, 2);
function cancelled_booking_order_status_cahnged_to_refund( $booking_id, $booking ) {$
// Get the WC_Order object from a booking
$order = wc_get_order( wp_get_post_parent_id( $booking_id ) );
// Update order status
if( is_a($order, 'WC_Order') )
$order->update_status('refund');
}
Code goes on function.php file of your active child theme (or active theme). It should works.
Documentation: Woocommerce booking developer documentation for filter and action hooks
I am writing a WooCommerce Plugin that takes care of payment and delivery.
Right now I am at the point of creating an order based on the current shopping cart.
That all works fine getting the items and costs correct, the only problem is that the order shows as being made by "Guest", instead of by the currently logged on user (even though the correct email address for that user is on the order).
Here is my code :
$cart = WC()->cart;
$checkout = WC()->checkout();
$order_id = $checkout->create_order();
$order = wc_get_order( $order_id );
$order->user_id = apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() );
$order->calculate_totals();
$order->payment_complete();
$cart->empty_cart();
Here is what I see in the backend after running this :
Why is the order placed as "Guest" instead of the user that placed the order?
And how do I get to have the correct user attached?
You will need to add _customer_user to post_meta table with order ID and meta value should be the user ID which you want to link to this order.
I hope that this will help you:
update_post_meta($order_id, '_customer_user', get_current_user_id());
OR
use user/customer id(create a customer/user before place order) in wc_create_order();
eg: $order = wc_create_order(array('customer_id' => $user));
this code fine for me!
I'm using woocommerce subscriptions and I'm writing a plugin to update an external system, if the user upgrade or downgrade his subscription it shows as a new order with its ID, but I can't get the subscription ID (which it's constant) related to the order ID, I check the documentation but I couldn't find a solution.
I was able to achieve like this.
$subscriptions = wcs_get_subscriptions_for_order($order_id, array( 'order_type' => 'any' ));
foreach( $subscriptions as $subscription_id => $subscription_obj )
{
$current_subs_id = $subscription_obj->get_id(); // This is current subscription id
$parent_id = $subscription_obj->get_parent_id(); // This is subscription parent id
}
You can access this data by hooking into the processed_subscription_payment action provided by WooCommerce Subscriptions:
add_action( 'processed_subscription_payment', 'se43079522_process_subscription', 10, 2 );
function se43079522_process_subscription($user_id, $subscription_key) {
// here you have access to the $subscription_key (ID) and the $user_id associated
}
Take a look at this link: https://docs.woocommerce.com/document/subscriptions/develop/action-reference/ for more information on the available actions with this plugin.
OR, you can do this manually like so:
Read comments for walk-through
global $woocommerce;
// Get the order ID and save as variable
$order_id = [ORDER_ID];
// Get the order object
$order = new WC_Order( $order_id );
// Loop through the subscription order
foreach ( WC_Subscriptions_Order::get_recurring_items( $order ) as $order_item ) {
// Get the subscription key
$subscription_key = WC_Subscriptions_Manager::get_subscription_key( $order->id, WC_Subscriptions_Order::get_items_product_id( $order_item ) );
}
// This is your subscription key (ID)
echo $subscription_key;
Get Subscription ID from Order. You can use wcs_get_subscriptions_for_order woocommerce function to get an object with the subscription related to that order and get the subscription ID from there.
$subscriptions = wcs_get_subscriptions_for_order($order_id);
var_dump($subscriptions);