In WooCommerce, I am using a custom function hooked in woocommerce_thankyou action hook, to execute some code after a payment has been made. The hook works but it seems that I can't get the order.
This is the simplified code. By the looks of it $order isn't found:
add_action( 'woocommerce_thankyou', 'afterorder', 10, 1 );
function afterorder($order_id) {
//$order = new WC_Order($order_id);
$order = wc_get_order($order_id);
$order_items = $order->get_items();
$order_comment_list = explode('\n', $order->customer_message);
$payment_method = $order->payment_method_title;
foreach( $order_items as $product ) {
$order->add_order_note('order for '.$product['name'].' received', false);
}
}
What am I missing here?
Your code is a partially outdated and with some errors since WooCommerce 3+. Order line items are now WC_Order_Item_Product class objects.
For Order "line items" you need to use WC_Order_Item_Product available methods to get the related data, like the corresponding product title:
add_action( 'woocommerce_thankyou', 'afterorder', 10, 1 );
function afterorder( $order_id ) {
// The WC_Order object
$order = wc_get_order($order_id);
$order_comment_list = explode( '\n', $order->get_customer_note() ); // Changed
$payment_method = $order->get_payment_method_title(); // Changed
foreach( $order->get_items() as $line_item ) {
// The WC_Product object
$product = $line_item->get_product(); // Added
$note = 'order for '.$product->get_title().' received';// Changed
$order->add_order_note( $note, false );
}
}
Code goes in function.php file of your active child theme (or active theme) or in any plugin file.
You should check may be the WC_Order method add_order_note() to see if you have correctly set it as you want.
Related
I am using this to create a new function in my functions.php file
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order() {
}
it is to execute some custom code when a new order is placed, how can i get the order information (ordered products etc) inside my function
You can use $order_id as a parameter for your woocommerce_new_order callback and get the order details from the $order_id.
Example:
// define the woocommerce_new_order callback
function create_invoice_for_wc_order( $order_id ) {
// get order details data...
$order = new WC_Order( $order_id );
var_dump($order);
};
References:
http://hookr.io/actions/woocommerce_new_order/
https://docs.woothemes.com/wc-apidocs/class-WC_Order.html
All answers here are correct but if you need the line items the above wont work since line items can't be fetched with new WC_Order at that time.
The hook now has a second $order parameter that will work.
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 2 );
function create_invoice_for_wc_order( $order_id, $order ) {
$items = $order->get_items();
// etc...
}
woocommerce_new_order includes an $order_id parameter. You can use it in your callback:
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order( $order_id ) {
$order = new WC_Order( $order_id );
$items = $order->get_items();
// etc...
}
If you want to get only the order details, You can use 'woocommerce_new_order' hook and $order_id as parameter
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order($order_id) {
$order = new WC_Order( $order_id );
print_r($order);
//your code
}
But if You want to get order items You should use 'woocommerce_checkout_order_processed'
add_action( 'woocommerce_checkout_order_processed', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order($order_id) {
$order = new WC_Order( $order_id );
//order items
$items = $order->get_items();
print_r($items);
}
The idea here is that when an order comes in with an "express delivery" as Shipping Method, the order status is updated to On-Hold.
As there I have some different "express delivery" Shipping Method rates I thought that by using stristr() to see if the word 'express' appears anywhere in the formatted shipping method title. But I seem to be missing something as I don't get anything.
How can I check if the Order shipping method is an "express delivery" to be able to update the order status?
Here is the code that I have:
add_action( 'woocommerce_thankyou', 'express_orders_4865', 10, 1 );
function express_orders_4865( $order_id ) {
global $woocommerce;
$order = new WC_Order( $order_id );
$shipping_method = $order->get_shipping_method();
if (stristr($shipping_method, 'express') === TRUE) {
$order->update_status('on-hold');
} else {
return;
}
}
EDIT-----------------------------------------------------------
For anyone using Woocommerce Table Rate Shipping the get_method_id returns the table rate id so i used get_method_title instead as below, if there is a better way please comment...
add_action( 'woocommerce_thankyou', 'express_shipping_update_order_status', 10, 1 );
function express_shipping_update_order_status( $order_id ) {
if ( ! $order_id ) return;
$search = 'Express'; // The needle to search in the shipping method ID
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Get the WC_Order_Item_Shipping object data
foreach($order->get_shipping_methods() as $shipping_item ){
// When "express delivery" method is used, we change the order to "on-hold" status
if( strpos( $shipping_item->get_method_title(), $search ) !== false ){
$order->update_status('on-hold');
break;
}
}
}
I prefer to use the faster and less memory intensive function strpos() instead as the shipping method ID is alway in lowercase (like a kind of slug).
So is better the get the WC_Order_Item_Shipping object data for this case, using the available methods.
So the code should be:
add_action( 'woocommerce_thankyou', 'express_shipping_update_order_status', 10, 1 );
function express_shipping_update_order_status( $order_id ) {
if ( ! $order_id ) return;
$search = 'express'; // The needle to search in the shipping method ID
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Get the WC_Order_Item_Shipping object data
foreach($order->get_shipping_methods() as $shipping_item ){
// When "express delivery" method is used, we change the order to "on-hold" status
if( strpos( $shipping_item->get_method_title(), $search ) !== false && ! $order->has_status('on-hold')){
$order->update_status('on-hold');
break;
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works…
So the code above didn't work for me, i had someone in a FB group help me debug it and this was the final one that worked for me
add_action( 'woocommerce_thankyou', 'express_shipping_update_order_status', 10, 1 );
function express_shipping_update_order_status( $order_id ) {
if ( ! $order_id ) return;
$search = 'express'; // The needle to search in the shipping method ID
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Get the WC_Order_Item_Shipping object data
foreach($order->get_shipping_methods() as $shipping_item ){
// When "express delivery" method is used, we change the order to "on-hold" status
if( strpos( $shipping_item->get_method_title(). $search ) !== false ){
$order->update_status('on-hold');
$order->save();
break;
}
}
}
My solution assumes that the normal status for a new order is PROCESSING.
So when an order is changed to PROCESSING, check the shipping method and if it matches, then change it to ON-HOLD.
add_action('woocommerce_order_status_changed', 'jds_auto_change_status_by_shipping_method');
function jds_auto_change_status_by_shipping_method($order_id) {
// If the status of an order is changed to PROCESSING and the shipping method contains specific text then change the status.
if ( ! $order_id ) {
return;
}
global $product;
$order = wc_get_order( $order_id );
if ($order->data['status'] == 'processing') { // if order status is processing
$shipping_method = $order->get_shipping_method();
if ( strpos($shipping_method, 'express') !== false ) { // if shipping method CONTAINS this text
$order->update_status('on-hold'); // change status to this
}
}
}
Note that $shipping_method returns the human readbale version of the shipping method that the customer sees, so you need to match exactly how the word 'express' appears to customer... is it 'express' or 'Express' or 'EXPRESS'
In WooCommerce, How to change the on-hold order status to something else, if this order has back-ordered items in it?
I have tried to use a custom function hooked in woocommerce_order_status_on-hold action hook without success.
Can anyone help me on this issue?
Thanks.
Here is a custom function hooked in woocommerce_thankyou action hook, that will change the order status if this order has a status "on-hold" and if it has any backorder products in it.
You will have to set in the function the desired new status slug change.
Here is that custom function (code is well commented):
add_action( 'woocommerce_thankyou', 'change_paid_backorders_status', 10, 1 );
function change_paid_backorders_status( $order_id ) {
if ( ! $order_id )
return;
// HERE below set your new status SLUG for paid back orders
$new_status = 'completed';
// Get a an instance of order object
$order = wc_get_order( $order_id );
// ONLY for "on-hold" ORDERS Status
if ( ! $order->has_status('on-hold') )
return;
// Iterating through each item in the order
foreach ( $order->get_items() as $item ) {
// Get a an instance of product object related to the order item
$product = $item->get_product();
// Check if the product is on backorder
if( $product->is_on_backorder() ){
// Change this order status
$order->update_status($new_status);
break; // Stop the loop
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
The code is tested and works.
function mysite_hold($order_id) {
$order = new WC_Order($order_id);
$items = $order->get_items();
$backorder = FALSE;
foreach ($items as $item) {
if ($item['Backordered']) {
$backorder = TRUE;
break;
}
}
if($backorder){
$order->update_status('completed'); //change your status here
}
}
add_action('woocommerce_order_status_on-hold', 'mysite_hold');
//You may need to store your backorder info like below
wc_add_order_item_meta($item_id, 'Backordered', $qty - max(0, $product->get_total_stock()));
Please try this snippet
edit code error on // Get a an instance of product object related to the order item
$product = version_compare( WC_VERSION, '3.0', '<' ) ? wc_get_product($item['product_id']) : $item->get_product();
I need to add custom args to PayPal paying link.
The PHP function looks like this:
$paypal_args = apply_filters( 'woocommerce_paypal_args', $paypal_args );
add_filter( 'woocommerce_paypal_args' , 'change_paypal_args' );
function change_paypal_args( $paypal_args ) {
global $wp;
global $woocommerce;
$order = wc_get_order( $order_id );
$paypal_args['invoice'] = 'spi432';
$paypal_args['txn_type'] = 'cart';
$paypal_args['payment_date'] = $order->order_date;
return $paypal_args;
}
I added txn_type and invoice as arguments to the link. But payment_date is not shown.
What may be the problem? Also, how can I display email of the customer?
If you enabled WP_DEBUG you would probably see that $order_id is undefined, and therefore $order is not an order object, so $order->order_date is likely a fatal error. Try passing the order as the second parameter instead.
add_filter( 'woocommerce_paypal_args' , 'so_42424283_change_paypal_args', 10, 2 );
function so_42424283_change_paypal_args( $paypal_args, $order ) {
$paypal_args['invoice'] = 'spi432';
$paypal_args['txn_type'] = 'cart';
// WC 2.6+
$paypal_args['payment_date'] = $order->order_date;
// WC 2.7
//$paypal_args['payment_date'] = $order->get_date_created();
return $paypal_args;
}
I am using this to create a new function in my functions.php file
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order() {
}
it is to execute some custom code when a new order is placed, how can i get the order information (ordered products etc) inside my function
You can use $order_id as a parameter for your woocommerce_new_order callback and get the order details from the $order_id.
Example:
// define the woocommerce_new_order callback
function create_invoice_for_wc_order( $order_id ) {
// get order details data...
$order = new WC_Order( $order_id );
var_dump($order);
};
References:
http://hookr.io/actions/woocommerce_new_order/
https://docs.woothemes.com/wc-apidocs/class-WC_Order.html
All answers here are correct but if you need the line items the above wont work since line items can't be fetched with new WC_Order at that time.
The hook now has a second $order parameter that will work.
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 2 );
function create_invoice_for_wc_order( $order_id, $order ) {
$items = $order->get_items();
// etc...
}
woocommerce_new_order includes an $order_id parameter. You can use it in your callback:
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order( $order_id ) {
$order = new WC_Order( $order_id );
$items = $order->get_items();
// etc...
}
If you want to get only the order details, You can use 'woocommerce_new_order' hook and $order_id as parameter
add_action( 'woocommerce_new_order', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order($order_id) {
$order = new WC_Order( $order_id );
print_r($order);
//your code
}
But if You want to get order items You should use 'woocommerce_checkout_order_processed'
add_action( 'woocommerce_checkout_order_processed', 'create_invoice_for_wc_order', 1, 1 );
function create_invoice_for_wc_order($order_id) {
$order = new WC_Order( $order_id );
//order items
$items = $order->get_items();
print_r($items);
}