I am trying to hook into a 3rd party application when a cart is checked out. Essentially i need to pass information about the order such as the products that are inside the order.
Everything i find points me towards the hook: woocommerce_new_order
When i use that hook i can get some information about the order but not everything.
add_action('woocommerce_new_order','order_check',10,1);
function order_check($order_id){
echo 'Order id is: '.$order_id;
$order = new WC_Order($order_id);
print_r($order);
echo '-----';
/** CHECK IF order has items */
$order_item = $order->get_items();
print_r($order_item);
exit;
}
For instance the above code sample will print the order array but when it call $order->get_items() nothing is returned.
At the time woocommerce_new_order fires, order items is not yet populated.
Instead, use the hook woocommerce_checkout_order_processed and you'll find that all items are then populated.
Related
I have a Wordpress installation with Woocommerce and I added a ACF field to the orders. It's called 'booking_reference'.
Inside my functions.php file, on checkout I update the 'booking_reference' custom field. It gets saved to the database. All is working as it should.
In my next function i'm trying to email this custom field to the customer. I use this code:
$order_id = $order->get_id();
$reference_number_acf_order = get_field('booking_reference', $order_id );
When I echo $reference_number_acf_order, it's empty. The $order_id variable is correct. It contains the order correct order ID.
The rest of the email to the customer is correct, it contains data from the order. Only the ACF value is empty.
Are u using WP_Query() or something like in your new function?
If so. try calling wp_reset_query(); first:
wp_reset_query();
$reference_number_acf_order = get_field('booking_reference', $order_id );
11/5/21 Update
It's really tricky that find out the wc_order couldn't access the calculate_totals and calculate_taxes.I find out the solution is put $order = wc_get_order( $order->get_id() ); before calulation. The 2 $order type is different , one is (object)WC_Order and another one is (Object)Automattic\WooCommerce\Admin\Overrides\Order. The method of second object works.
I wanna make the AJAX function to place an order programmatically. The product price is base on metadata so I have to calculate every line item. It doesn't with any issue from the client side that sends the post the request to place. The problem point, even I set the price to the line item, and use calculate_totals for the WC_Order but the price didn't correct. The only correction is the cost and subtotal. Though I hit the recalculate button the price would be right.
code
function place_an_order($data){
$screen_prodcut = new WC_Product_Simple(6310);
$userid = get_current_user_id();
$order = wc_create_order(array('customer_id'=>$userid));
$screen_quantity = 2;
$item_id = $order->add_product($screen_prodcut,$screen_quantity);
wc_add_order_item_meta($item_id,'width','1201');
wc_add_order_item_meta($item_id,'height','1201');
wc_add_order_item_meta($item_id,'note','** this is testing**');
$screen_price = 50;
$new_line_screen_price = $screen_price * $screen_quantity;
$item = $order->get_item($item_id);
$item->set_subtotal( $new_line_screen_price / 11 * 10 );
$item->set_total( $new_line_screen_price / 11 * 10 );
$item->save();
// ###section 1###
$order->calculate_taxes();
$order->calculate_totals();
// ###section 2###
}
When run in section 1, the $item subtotal and total are correct. But run in section 2 there is the failure out when printing $order and retrieve the total is wrong. In the dashboard, the price would be shown wrong but the total and subtotal are correct.
After clicking the recalculate, the order total is corrected.
I have no idea why calculate_totals and calculate_taxes don't work. woocommerce_calc_line_taxes is the AJAX action via hit the recalculate button. Usage is calculate_totals and taxes as well. Alternatively, I have to use the set_total instead of calculate_totals?
I've created a hook for WooCommerce when an order is cancelled like so:
add_action( 'woocommerce_order_status_cancelled', 'prefix_order_cancelled_hook' );
function prefix_order_cancelled_hook($order_id){
write_log("Order ${order_id} has been cancelled")
}
Now when the status changed to cancelled, the hook is invoked as expected but the output execution is not what I'm expecting. I'm getting the following in the log:
Order 4 has been cancelled
Order 5 has been cancelled
Order 6 has been cancelled
I've seen that this corresponds to the number of orders I currently have on the store. Can someone help with why this is happening and how to only run the hook once for the changed order.
Seems like your code is executed for all orders. So there seems to be a problem with the $order_id. I think you can't access properties directly, but need to get an instance of the WC_Order object (since Woocommerce 3.0+ something about) like:
add_action( 'woocommerce_order_status_cancelled', 'prefix_order_cancelled_hook' );
function prefix_order_cancelled_hook($order_id){
// get an instance of an WC_Order object
$order = wc_get_order( $order_id );
// get the ID of the order
$order_id = $order->get_id();
write_log("Order ${order_id} has been cancelled")
}
I have the following code snippet:
add_action('woocommerce_new_order', 'foo_function', 10);
If I create a new order from the admin panel, this fires just fine.
However, creating it via the REST API will not fire the function.
Why is that?
Update
I've tried using the following:
woocommerce_rest_insert_shop_object – this one doesn't fire at all.
wp_insert_post and save_post – they do fire, but don't contain the line items... (on the first run, it's an empty list, and on the second run (where the $update flag is true) there is an item but that item has no data (like product id or quantity).
add_action( "woocommerce_rest_insert_shop_order_object", 'your_prefix_on_insert_rest_api', 10, 3 );
function your_prefix_on_insert_rest_api( $object, $request, $is_creating ) {
if ( ! $is_creating ) {
return;
}
$order_id = $object->get_id();
$wc_order = new WC_Order( $order_id );
do_action( 'woocommerce_new_order', $order_id, $wc_order );
}
You have tried woocommerce_rest_insert_shop_object,
but the hook is woocommerce_rest_insert_shop_order_object
Please use this hook woocommerce_process_shop_order_meta instead of woocommerce_new_order As far as I can determine, woocommerce_new_order is only fired when an order is processed through the checkout. In a lot of instances, staff were creating orders in the wp-admin and assigning them straight to processing or completed, which meant that hook wasn't doing what I thought it would. Using woocommerce_process_shop_order_meta will solve it for you.
On v2 there is the woocommerce_rest_insert_{$this->post_type}_object filter
So the correct hook for what you need is woocommerce_rest_insert_shop_order_object
this is very strange, i am calling $order = new WC_Order(52); and I get a correct order object but the Items array is empty.
Any ideas whats going wrong ?
I am using WooCommerce 3.4.3.
I also thought what you are doing should work but in fact it is wrong. I read the WooCommerce source code and this is how WooCommerce does it.
if ( ! $order = wc_get_order( $order_id ) ) {
return;
}
$order_items = $order->get_items( apply_filters( 'woocommerce_purchase_order_item_types', 'line_item' ) );
The $order->get_items() call will check if the line item has been read from the data store and read it if it has not yet been read. So, new WC_Order(52) actually only partially initializes the order object. The order items are initialized later when they are accessed through the order. This may be more efficient as items that are not used will not be initialized. Please note that the order is created by using the wc_get_order() function. You should do this instead of new WC_Order() as this uses the factory to create the order.
The solution provided here is correct. However if you are trying to get the order items on woocommerce_new_order it will not solve your problem since line items are assigned to the order after the woocommerce_new_order hook is triggered.
I only managed to sort my issues after I changed the hook to woocommerce_checkout_order_processed as per below:
add_action( 'woocommerce_checkout_order_processed', 'get_order_items_on_checkout', 50, 3 );
function get_order_items_on_checkout($order_id, $posted_data, $order){
$items = $order->get_items();
}