Is there a hook I can use when I make a change to someone's order via the admin (such as their address, or a custom meta field)? I read this question but unfortunately woocommerce_process_shop_order_meta is fired before the order is saved, meaning I have no access to the newly updated data. What I need is to be able to use the new data that is saved to the order.
UPDATE: An issue with using save_post_shop_order is that the meta is updated before this is hit, so I can't compare the previously saved meta value, for example:
$metaArray = $_POST['meta'];
foreach($metaArray as $meta => $key) {
$metaArr[$key["key"]] = $key["value"];
}
$meta = get_post_meta($order->ID);
if($meta['coverstart'][0] != $metaArr['coverstart']) {
die("COVER START DATE HAS CHANGED");
}
The die() is never hit, because the script always gets the newly saved value.
Sorry but woocommerce_checkout_update_order_meta is fired after the order is saved… See this extract source code located in WC_Checkout create_order() method:
// Save the order.
$order_id = $order->save(); // <== Order is saved here before
do_action( 'woocommerce_checkout_update_order_meta', $order_id, $data ); <== // The hook
return $order_id;
So in woocommerce_checkout_update_order_meta you can get the saved order data:
by retrieving the WC_Order object from the $order_id argument and using all methods on it.
or using get_post_meta() on with the $order_id argument to get the data saved in wp_postmeta database table.
Then you can update the data with update_post_meta() function…
You can even use woocommerce_checkout_create_order before the data is saved…
You will be able to get the data from the $order argument using all available methods for the WC_Order class (CRUD getters methods).
You will be able to alter this data and saving it using the CRUD setters methods…
Some examples in stackOverFlow
If you need to do that after the order process the hooks to be used can be:
woocommerce_new_order (on newly created order event)
woocommerce_thankyou (on order received page)
woocommerce_order_status_changed (on order status changing event)
And may be some others…
To alter the data when order is saved in backend, you will use save_post_shop_order that has 3 arguments: $post_id, $post and $update…
Related
I'm creating a custom shipping calculator for my WooCommerce store. I need to collect some extra form data from the user to calculate the shipping properly.
I have the form fields added to woocommerce_checkout_after_customer_details. I can probably get this into the cart page without much trouble once I figure out the checkout page functionality, so let's focus on this.
I have a class extending WC_Shipping_Method with a calculate_shipping method a la this tutorial.
In that method, I want to use the extra form data (plus the destination) to calculate the shipping for that customer. Right now I just have this adding a dummy rate, which shows up.
I also created a custom cart-shipping.php file to not show any inputs for the available method in the order review cart, just the label and cost. Since the picking happens in my custom form, having options here is unnecessary.
Am I doing this right, or is this approach super hacky?
If this is the correct approach, how do I access the extra form fields inside the calculate_shipping method?
Have tried
Named the final options in my custom form shipping_method_* which triggers the wc-ajax=update_order_review call... which inits my custom shipping method class, but does not appear to ever call the calculate_shipping method anyhow. The only time this method seems to be called is when I'm actually adding a product to the order.
Also tried
Defined all of my possible delivery options and added them in calculate_shipping like $this->add_rate( $rate );. I think then I can somehow select one (force the user into one) when the cart updates via update_order_review ajax call? Again, the set option should be determined by these fields the user interacts with on the checkout form. But I haven't figured out how to set the shipping on that action yet.
calculate_shipping() is not always called
First off, you should know that the calculate_shipping() method of your shipping method class will only be called when the shipping rates are calculated for the first time (in the current WooCommerce session), each time after a product is added to the cart, and whenever the shipping address is changed — from the cart or checkout page.
But of course, a plugin or custom code can programmatically call the method (or re-calculate the rates) at any times. However, the default behavior is as follows:
Rates are stored in the session based on the package hash to avoid
re-calculation every page load.
And the calculate_shipping() method is executed by the WC_Shipping class through its calculate_shipping_for_package() method. In fact, the above quote was taken from the description of WC_Shipping::calculate_shipping_for_package() which calls WC_Shipping_Method::get_rates_for_package() and eventually the calculate_shipping() method in your own class.
How to get the submitted value of a form field in the checkout form from the calculate_shipping() method
So if you have this in the checkout form:
<input type="text" name="my_field"...>
Then you can get the submitted (POSTed) value using either the $_POST superglobal or the WC_Checkout::get_value() method:
$_POST['my_field']
WC()->checkout->get_value( 'my_field' )
It's as simple as that. :)
To ensure calculate_shipping is called
Run something similar to the following to clear out the session information, which will indicate that calculation still needs to be done. Be aware that if you do this on every page, it will mean that the shipping is constantly being recalculated when it doesn't need to be.
$packages = WC()->cart->get_shipping_packages();
foreach( $packages as $package_key => $package ) {
$session_key = 'shipping_for_package_'.$package_key;
$stored_rates = WC()->session->__unset( $session_key );
}
I'm not sure if this is the best way to accomplish this, but currently I am making this work by setting a session value on woocommerce_checkout_update_order_review and then accessing that value in my calculate_shipping method.
Looking at the WooCommerce documentation, it seems their desired way for you to access things such as user location from the calculate_shipping function is to use their Settings API. https://docs.woocommerce.com/document/settings-api/. Read the docs to see exactly how, but here is a simplification:
Read the location using
$this->init_settings();
$this->location = $this->settings['location'];
Write/Set the user's location with this table:
<?php function admin_options() {
?>
<h2><?php _e('You plugin name','woocommerce'); ?></h2>
<table class="form-table">
<?php $this->generate_settings_html(); ?>
</table><?php
}
The table would be made with
function init_form_fields() {
$this->form_fields = array(
'location' => array(
'title' => __( 'Location', 'woocommerce' ),
'type' => 'text',
'description' => __( 'This is the users address.', 'woocommerce' ),
'default' => __( 'none', 'woocommerce' )
)
);
}
I need to run some custom PHP code when an order is placed on a WooCommerce store. Currently, I am using woocommerce_order_status_changed hook which is working perfectly for web front.
add_action('woocommerce_order_status_changed', 'order_confirmation',10, 3);
function order_confirmation($order_id,$oldstatus,$newstatus){
//my custom code...
}
But when an order is placed through API, this hook is not called.
Is there any hook that we can use to execute some php code when an order is placed through WooCommerce's Rest Api V2?
i think you are sending the set_paid property to true. It sets the status to processing and reduce stock items. if you need to to perform action when order payment is completed, you can use the woocommerce_payment_complete action hook.
function on_woocommerce_payment_complete($order_id){
}
add_action( 'woocommerce_payment_complete', 'on_woocommerce_payment_complete'
);`
However the above hook only fire when order status was from the following array
on-hold', 'pending', 'failed', 'cancelled
before marking the payment completed.
For other order statues the following hook is fired.
do_action( 'woocommerce_payment_complete_order_status_' . $this->get_status(), $this->get_id() );
For more detail you can check the
public function payment_complete( $transaction_id = '' ) {
define in
woocommerce\includes\class-wc-order.php
When the user buy a product, I want to save a series of data in custom tables in database. This data will be the product id, custom fields I have, and some other data.
My idea is that this should be done when the payment of the product has been made correctly, that is to say, at the time of payment.
I wanted you to give me advice, I have created a way but I don't know if it is the right one or if you would recommend any other way.
I've edited the thankyou page, and I have inserted this code:
$order = new WC_Order ($order->get_id ();
$check_payment = $order->payment_complete ();
if ($check_payment) {
global $wpdb;
wpdb->insert (/* CODE DATABASE*/);
}
As woocommerce Order-received (thankyou) page can be reloaded, it's not really the good way.
The correct hook to be used that you can find inside WC_Order payment_complete() method is woocommerce_payment_complete. So your code should be for most payment gateways:
add_action('woocommerce_payment_complete', 'action_payment_complete', 30, 1 );
function action_payment_complete( $order_id ){
global $wpdb;
// Get an instance of the WC_Order object (if needed)
$order = wc_get_order( $order_id );
// Your database actions code
wpdb->insert (/* CODE DATABASE*/);
}
Code goes in function.php file of the active child theme (or active theme).
For payment methods (CHEQUE HERE) as 'cheque', 'bacs' and 'cod' that needs to be "completed" by shop manager, you will use instead:
add_action( 'woocommerce_order_status_completed', 'action_order_status_completed', 20, 2 );
function action_payment_complete( $order_id, $order ){
// The specific payment methods to be target
$payment_methods = array('bacs','cheque','cod');
// Only for specific payment methods
if( ! in_array( $order->get_payment_method(), $payment_methods ) return;
global $wpdb;
// Your database actions code
wpdb->insert (/* CODE DATABASE*/);
}
So when order status will change to completed for this specific payment methods, this hook will be triggered…
You can also use instead woocommerce_order_status_processing if you target Processing order status or woocommerce_order_status_on-hold if you target On Hold order status
Code goes in function.php file of the active child theme (or active theme).
This should works.
I am a total beginner in programming with PHP. I wanted to create a PHP file in which the order_status from a predefined order (in my case 108) gets changed to completed.
Therefore I need the woocommerce functions get_order($ID) and update_status but I do not know how to use them in my PHP. I hope you understand my problem. From Java I could imagine that I need to get an instance from a class or something like that?
Here is the code I have so far:
<?php $ord = new WC_Order(108); $ord->update_status('completed'); ?>
When I open the page I receive the following error:
Fatal error: Uncaught Error: Class 'WC_Order' not found (...)
In general on Wordpress/WooCommerce you will include your functions code:
In your active child theme (or active theme) function.php file
In a plugin…
You can also enable some code in:
Your theme templates
WooCommerce templates that you will override through your active child theme (or active theme).
Now to execute that function, you will need an event that will execute your function.
In (Wordpress) Woocommerce there is a lot of action hooks that are triggered on some specific events that you can use to execute your function. In this case your function will be hooked (ready to be executed on a specific event).
If you want to change the status of a specific order is better to do it in the related order edit page in backend.
An example:
For example you can change the order status when a customer has submit his order after checkout on order-received end point (thankyou page):
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_order');
function custom_woocommerce_auto_complete_order( $order_id ) {
if ( ! $order_id ) return;
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Change order status to "completed"
$order->update_status( 'completed' );
}
This code is an official code snippet: Automatically Complete Orders.
It is a good example that shows you how things can work… So in your case you are using here WC_Order class methods like update_status().
Now with this code base, you can refine the behaviors like in this answer:
WooCommerce: Auto complete paid Orders (depending on Payment methods)
Related to orders: How to get WooCommerce order details
I have been searching for hours...
I can't figure out how get a function to be executed when clicking "save" after editing the quantity of a product in an existing order.
I tried this:
add_action('woocommerce_order_edit_product', 'your_function_name');
function your_function_name(){
//my php function code would be here
}
but the your_function_name function is not being called when clicking save.
I tested the function and when calling it directly it works as it should, so I think I got the wrong hook...
after wrestling with this issue for 2 days now, i found it: there is two hooks, one before and one after saving:
woocommerce_before_save_order_items
woocommerce_saved_order_items
both are fired when saving an order in the backend. one before the save and one afterwards.
both two hooks carry the same variables: $order_id (int) & $items (array)
i guess with the first hook, you could get the old order and compare its contents with the items array to see what has changed. at least this is what i try to accomplish now.
so this is how you would trigger this:
add_action( 'woocommerce_before_save_order_items', 'so42270384_woocommerce_before_save_order_items', 10, 2 );
function so42270384_woocommerce_before_save_order_items( $order_id, $items ) {
echo $order_id;
var_dump( $items );
}
be aware..
adding a product to an exitsting order does implement another hook that gets called before this (so when hitting SAVE, the above function will fire, but the order and its items are already set BEFORE saving (when adding a product, the order will save immediately). that means $order = new WC_Order( $order_id ); will have the new items already in it, before and after, so there is no way to find, what has changed.). but the woocommerce_ajax_add_order_item_meta hook is triggered on 'add product' and helped me on that end. happy coding everyone..
Check your error log. Should be some info there. If I am looking at the correct action it takes four arguments:
do_action( 'woocommerce_order_edit_product', $this->id, $item_id, $args, $product );
So your code should be:
add_action('woocommerce_order_edit_product', 'your_function_name', 10, 4);
function your_function_name($id, $item_id, $args, $product){
//my php function code would be here
}