How can WooCommerce customers edit an order they just placed and paid for? I swear I looked on search engine results and other places before coming to the conclusion I needed to code this myself.
For example, a user might want to change the delivery date (if you provide this on the checkout page). Or maybe they need to change size, or make up their mind about a given product in the order.
Either way it’s shocking to me this functionality is not in a plugin – as usual if you’re interested in customizing this snippet/plugin for your specific needs feel free to get in touch.
So, let’s see how it’s done!
Snippet (PHP): Allow Customers to Edit Orders @ WooCommerce My Account Page
The first thing we need is to show the “Edit Order” button for Processing Orders only. Here, I’m just taking advantage and reusing the “Order Again” functionality that WooCommerce offers – this “Order Again” basically duplicates the given order and fills the Cart with the same products and meta.
If you get my point, “Edit Order” is the same as duplicating the order you want to edit, placing a new order and deleting the previous one. At least this is how I see it and it comes definitely easier in this way.
In order to show the “Edit Order” button for processing orders, we need to unlock the “Order Again” button (“woocommerce_valid_order_statuses_for_order_again” filter). By default this only displays for completed orders – we need processing too (part 1).
Now I can print the “Edit Order” button with “woocommerce_my_account_my_orders_actions” filter. As you can see, the “add_query_arg” must have “order_again” so that clicking the button triggers an order again function, and also I add a second “add_query_arg” equal to “edit_order” so that I know the Edit Order button was clicked and not the Order Again. The button “name” changes to “Edit Order” (part 2).
Great – now the button will show under My Account > Orders for processing orders, and on click this will redirect to a Cart URL that will contain a parameter (and the Cart will be filled out with the same products, thanks to “order_again” parameter). I can now simply “listen” to this and see whether the button was clicked during “woocommerce_cart_loaded_from_session”. I can use “$_GET” to see whether the URL contains parameters – and if yes I add the edited order ID to the cart session (part 3).
Now I move to parts 4 and 5: I want to show a Cart notice that the cart has been filled with the same products of previous order, and also that a “credit” has been applied to the current cart in form of discount (“add_fee”) – yes, it’s a discount that is equal to the same value of the order total paid previously.
Update January 2019: please note that add_fee() does not work well when using negative amounts AND you have taxes enabled. In this case you’d need to find an alternative.
And then we move to the final section, part 6: if customer places the order, we clearly need to cancel the “edited” order and to show a notice in the order admin page of both orders, including a link to the relevant order (cancelled or new, respectively). For this, I use the “add_order_note” function.
Well, a long explanation but hopefully this is helpful 🙂
/**
* @snippet Edit Order Functionality @ WooCommerce My Account Page
* @how-to businessbloomer.com/woocommerce-customization
* @sourcecode https://businessbloomer.com/?p=91893
* @author Rodolfo Melogli, Business Bloomer
* @compatible WooCommerce 4.1
* @community https://businessbloomer.com/club/
*/
// ----------------
// 1. Allow Order Again for Processing Status
add_filter( 'woocommerce_valid_order_statuses_for_order_again', 'bbloomer_order_again_statuses' );
function bbloomer_order_again_statuses( $statuses ) {
$statuses[] = 'processing';
return $statuses;
}
// ----------------
// 2. Add Order Actions @ My Account
add_filter( 'woocommerce_my_account_my_orders_actions', 'bbloomer_add_edit_order_my_account_orders_actions', 50, 2 );
function bbloomer_add_edit_order_my_account_orders_actions( $actions, $order ) {
if ( $order->has_status( 'processing' ) ) {
$actions['edit-order'] = array(
'url' => wp_nonce_url( add_query_arg( array( 'order_again' => $order->get_id(), 'edit_order' => $order->get_id() ) ), 'woocommerce-order_again' ),
'name' => __( 'Edit Order', 'woocommerce' )
);
}
return $actions;
}
// ----------------
// 3. Detect Edit Order Action and Store in Session
add_action( 'woocommerce_cart_loaded_from_session', 'bbloomer_detect_edit_order' );
function bbloomer_detect_edit_order( $cart ) {
if ( isset( $_GET['edit_order'], $_GET['_wpnonce'] ) && is_user_logged_in() && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'woocommerce-order_again' ) ) WC()->session->set( 'edit_order', absint( $_GET['edit_order'] ) );
}
// ----------------
// 4. Display Cart Notice re: Edited Order
add_action( 'woocommerce_before_cart', 'bbloomer_show_me_session' );
function bbloomer_show_me_session() {
if ( ! is_cart() ) return;
$edited = WC()->session->get('edit_order');
if ( ! empty( $edited ) ) {
$order = new WC_Order( $edited );
$credit = $order->get_total();
wc_print_notice( 'A credit of ' . wc_price($credit) . ' has been applied to this new order. Feel free to add products to it or change other details such as delivery date.', 'notice' );
}
}
// ----------------
// 5. Calculate New Total if Edited Order
add_action( 'woocommerce_cart_calculate_fees', 'bbloomer_use_edit_order_total', 20, 1 );
function bbloomer_use_edit_order_total( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$edited = WC()->session->get('edit_order');
if ( ! empty( $edited ) ) {
$order = new WC_Order( $edited );
$credit = -1 * $order->get_total();
$cart->add_fee( 'Credit', $credit );
}
}
// ----------------
// 6. Save Order Action if New Order is Placed
add_action( 'woocommerce_checkout_update_order_meta', 'bbloomer_save_edit_order' );
function bbloomer_save_edit_order( $order_id ) {
$edited = WC()->session->get( 'edit_order' );
if ( ! empty( $edited ) ) {
// update this new order
update_post_meta( $order_id, '_edit_order', $edited );
$neworder = new WC_Order( $order_id );
$oldorder_edit = get_edit_post_link( $edited );
$neworder->add_order_note( 'Order placed after editing. Old order number: <a href="' . $oldorder_edit . '">' . $edited . '</a>' );
// cancel previous order
$oldorder = new WC_Order( $edited );
$neworder_edit = get_edit_post_link( $order_id );
$oldorder->update_status( 'cancelled', 'Order cancelled after editing. New order number: <a href="' . $neworder_edit . '">' . $order_id . '</a> -' );
WC()->session->set( 'edit_order', null );
}
}
Can you set the order status to “cancelled” as soon as edit is pushed? This would resolve issues around single use coupons/loyalty points, also stop stock being held or orders being packed whilst a user edits an order.
Hi Matt, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Code works great, however how do you handle a scenario where a customer clicks “edit” and is placing a new order, but whilst this is happening your warehouse packs the order and changes the status to “completed”? In my testing it still allowed me to checkout and it cancelled the order with “completed” status and made a new “processing” order, which means the original order and a new one will be dispatched. Not sure if you when a customer clicks “edit” it should change the order status to “on hold” however it would need to revert if the customer leaves without editing.
You make great points, I’m sure this can be adapted to your requirements!
Hi, Thanks for sharing the solution,
I didn’t tried it yet, but is there any chance to add an expiry timer for letting customers know how much they have time to edit their current order?
for example: I want they have only 1 hour to able edit the order. and at the end of time, the edit button get disable and show a msg instead.”Sorry, You can’t add more product anymore.”
Thank You
Hello Behnam, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Hi Rodolfo,
this is exactly the snippet I need… however, when I paste it into my functions.php I get “syntax error, unexpected ‘ ‘ (T_STRING)”.
Any ideas what to do?
Please make sure you copied everything and didn’t forget a single character. Usually the error log would tell you the line number where the error occurs, and that should help you. Let me know!
Hi,
Edit order not possible if product is out of stock in wordpress. This bug exists for products that have limited inventory. please help me
Great feedback, thank you.
Cancelled orders already restore stock by design:
I think you simply need to reorder content inside the bbloomer_save_edit_order() function: you first cancel the old order, and then you create the new one.
Let me know
Hi, can you post a full code snippet with reordered content so the order is first canceled?
As I’m not coding guy and I fail to do it?
Thanks!
Hello, when order duplicates all the public order notes are deleted with the old order (the order that was duplicated). Is it possible to duplicate order with notes included?
Also do you know any solution how to manage emails sent to customer? Now the customer gets an email when I add the order, then he gets two more emails about cancelled order and new order (duplicated order)…
Hi Kasparas, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Hi,
Very useful snippet thank you. I have one issue – the new order pulls in meta labels of custom fields into the cart and onto emails – these labels are hidden on the original order as they are not for display (from a product addons plugin). I can hide these labels in cart using css, but not sure about hiding on emails? Any idea why they appear at all?
Thanks
Richard
Hi Richard, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
The snippet is functioning, however I have a question. I’ve installed this plugin https://wordpress.org/plugins/product-input-fields-for-woocommerce/ in order to allow the user to put some custom text in the item order, however this is not available in the new edit, how could that be achieved?
Hi Luis, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Hi, This code is great! Working perfectly.. just one thing want to know.. is it possible to limit the ability to edit the order for 2 hours from the time of checkout? If so, can you please give me a coding for that. I tried, but couldn’t do it bro 🙁
Hey John, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
You really should include a payment gateway check somewhere in the code.
Why? – Because as of right now, the customer can order something using an offline payment gateway, edit the order and add an additional item and only having to pay for that one item.
Example scenario:
Customer orders two items for a total of $500.00
Customer places order using an offline gateway.
Customer edits the order and adds an additional item to the order. This extra item costs €10.00 (as an example)
The customer now only has to pay $10.00 for all three items.
Thanks Sara. Good idea, but this is a short snippet and therefore it can’t do “everything”. If you want to share your customized version, feel free to do it here.
Hi,
Snippet is pretty old but still very useful and works great (in WooCommerce 4.1, I only remove the credit part as I don’t need it) ! Thank you !
Nice!
Thanks for this. It’s an interesting approach.
However there are a couple of important bugs in your code.
One is, as Erika identified above, your code continues to apply the same discount to every new order that’s placed in the same session. If I order something for £30, then edit that order, then place a bunch of new orders, I will get £30 off every order as long as I stay logged in! You need to clear that session variable once the replacement order is placed.
Secondly, there are no security checks on the supplied GET variable edit_order. I can enter any valid order number here by simply specifying ?edit_order=1234. It doesn’t matter whose order that is, or what status it is; your code applies the total of that order as a discount to me, and then sets that order’s status to cancelled when I submit my order.
The order_again() function in class-wc-form-handler.php performs a number of security checks, including verifying the nonce and that the user is authorised to access that order (i.e. it’s their own order). Your code needs to do something similar before accepting the edit_order GET arg or it’s wide open to abuse.
Excellent, Ben, that’s why I don’t develop plugins 🙂 If you wish to send the revised version I’ll upgrade you to co-author. Cheers!
FYI, I’ve revised the snippet and it should now be ok
It is not okay! What Ben wrote above still applies, I just deleted the snippets and changes my perception about you completely! Better no snippets than snippets full of bugs!
Oh yes, it is okay. Good luck!
Hi! Thanks so much for providing this code. It seems to be working almost exactly as you stated, EXCEPT it seems to be duplicating both the edited order and the original canceled order. In other words, I end up with three active orders: one of the original and two of the final.
For example, my initial order was order #1734 in the amount of $22.39. After editing the order, #1734 was canceled, and a new (duplicate) order #1735 in the amount of $22.39 was created with status = “processing.” In the final version of my order, I had removed one of the items from the original order and replaced it with another one. Once I submitted the edited order, I showed two duplicate “final orders,” #1741 and #1742, both in the amount of $15.04. So, in my WooCommerce dashboard, I’m showing three active orders that need to be fulfilled, where there should only be one since #1735 is incorrect (one product was removed) and #1741 and #1742 are duplicates.
The credit for $22.39 was still appearing in my cart when I tried to place a new separate order as well. This was still happening even after using the code Erika provided in the comments.
Is this snippet designed to create multiple final orders and to leave the credit in the cart?
Thank you Ashley. When you “edit” an order, it sends you to Cart with a credit applied (because you already paid). It should therefore only create this new order, as long as you checkout. Remaining credit won’t be kept, and no order duplicates will be generated. Can you try with a different theme and no other plugins than Woo?
after click button “edit” I got empty page with url /easyshop/my-account/orders/?order_again=2991&edit_order=2991&_wpnonce=451bdafbb9
Hi Kyryl, thanks so much for your comment! Yes, this is possible, but I’m afraid it’s custom troubleshooting work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Hello,
Thanks for sharing this knowledge with us .. I have a question, My website is using WCMP market place … Can i add this function for vendors to be able to edit their orders quotations ?
As my vendors can receive ” Request a quote ” from clients but can’t make any edits on it.
So is this possible ?
Bassem, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
I need to make orders editable by customer for fixed time.
Example, client can edit/cancel order for 30 minutes after placing it, after 30 minutes order status will be changed to processing and client edit or cancel anymore!
What should I do then? TIA
Nasir, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
I understand the flow but I am thinking what if the order is paid thru credit card and they want to edit it? Would they get a refund? How would this work?
If they already paid, you can always issue partial refunds etc. Always a manual operation though.
Hi,
Stumble upon this post, it is a great post on how to allow customer to change their order by themselves.
I have an issue, there are always customers order items and already make payment waiting for us to process the order, suddenly customer contacts us that they order the wrong variation, how to edit the variation before we can proceed to “complete” order?
etc: Customer order “Blue Color”, but they contact us that they wanted to change to “Yellow Color”.
Since we not yet ship out the product to our customer, suppose we could change the variation before we mark “complete” status.
I could not find a way to edit the customer items to change it color according to their request.
Any plugin can help me with my problem?
Hope to hear from you.
As an admin, you can edit orders by temporarily set them to “on-hold” and then mark them again as processing
Seems that woocommerce edit Order is such tedious, any idea or plugin so that admin can edit Order changing variant similar to customer interface? etc: open up a new browser for that particular product page.
Please advice. Thank you.
I know, probably you need custom coding for that
Dear Kind Rodolfo,
Thank you very much for your very kind and professional effort for the internet people community and your code works flawlessly amazing!
I’ve one question, Sir. Can you kindly help to make the edit order for “Payment Pending” status too?
I’ve tried this but I received syntax error:
And i’ve also tried this:
Of course, I tried to change same thing for this section:
OR
I am struggling with this, sir.
I hope to receive a reply.
Thank you in advance.
Hello Toren, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
you can use it like
Hi Rodolfo,
really nice explanation and thanks for writing the code. I “installed” your code but after clicking Edit Order it redirects to an empty basket.
1. click on edit order => page_id=15&orders&order_again=966&edit_order=966&_wpnonce=c881de3191
2. 302 to => ?page_id=13 (basket page)
“error message”: basket is empty.
Im a php developer and could figure it out by myself but im kinda new to wordpress/woocommerce. so before looking at everything,
do you have a tipp where i should look first to get it running?
Thanks in advance.
Best
Majk
Did you click on edit order from the My Account page right?
I am using this code but I can face this problem “Product can’t be added to cart.”
Is the product in stock?
Hello!
I am looking for an option to let customers edit their processing orders and this is the closest I have seen… maybe you can point me in the right direction?
I have woocommerce bookings, and am using it to book bands for venues. Once the band confirms the booking, the order status will stay processing until the customer hits the “Performance Complete” button. This then will change the order to complete.
There are a few situations where venues will want to add more to the bill after the performance. The most common would be to add a tip to bands after the show. Another reason would include, some venues pay bands based off the percentages of the business… so if the venue has a better night, the band gets paid more.
Problem is with booking orders, when the customer hits the order again button, or the edit order button from your code, I get the error that a duration must be selected. It seems the duration data isnt able to transfer back and forth?
Probably custom work, but I figured i’d ask! I have looked everywhere for a solution to the same “order again” button but have had no luck!
Hello Nick
Maybe that’s a Booking plugin bug? Try ask the support team
This is really great! I was wondering if it’s possible (you don’t have to code it) to allow the same order to be used for the new items instead of cancelling the old order and creating a new one?
Thanks
Hello Josh, yes, everything is possible 🙂
Hi, thanks a lot for the code, it’s fantastic.
I have only one problem that I don’t understand how to do.
I have 3 payment methods; PayPal, bank transfer and cash on delivery
I would need that if the customer has already paid as with PAYPAL or CREDIT CARD your code is fine.
But my problem is cash on delivery or bank transfer, as it gives me a discount while the customer has not yet paid the order.
I need you to apply add_fee only if the payment is paypal or credit card
While if bank transfer or cash on delivery regenerates the order without applying the credit?
How can I do? Thank you
Ciao Pietro, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Hello Rodolfo, I need to allow the client to edit custom fields that I entered in the checkout form. It’s possible? Can you help me?
Hi Leo, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
From the original order stock is removed from woocommerce, and on the second pass stock is removed again. What is the best solution to get around the double-dip?
Hi Mike, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!
Edit Processing Orders does not work on WooCommerce 3.5.7. Please test, thanks.
Hi Kinh, thanks for your comment. Worked for me on 3.5.7 and Storefront theme. Sorry!
Hi Rodolfo! Thank you very much for sharing this snippet, i had to make this for a client and you put me on the right path. I just want to share with you two changes i had to make in order for it to properly work with WooCommerce 3.5.7. In the function bbloomer_save_edit_order i’ve added a reset for the value “edit_order” in the session, because without the reset it continued to apply the credit in all future orders. In the same function i’ve changed how you retrieve the link for the new and old order: get_edit_post_link was returning me null, because it seems that the function works with the builtin WordPress post types, and not with the WooCommerce ones. Oh, also added some i18n 🙂 This is my final code:
Thank you again!
AWESOME!
I have a doubt …
This code provides an edit, or what it really does is re-insert an order in the cart?
Edit, for me, is when it is done in the same order number.
If this code creates a new order, and if the “previous” order takes on a new status, then I do not think it’s an edition, rather it would be something like “Re Order”
Correct me if I’m wrong.
Greetings.
You’re not wrong, this is what I came up with to make it work for my client… if you need something different than you’ll need to customize it. Hope this makes sense 🙂
Hi Rodolfo,
I tried your code but seems like there are one big bug inside… Basically, when customer try to edit the order, the new order price difference is only presented NOT the whole price (for edited products plus new products). E.g. Let’s say in first order there are 10 products total of 1200$. In edited order is 12 products with total of 1450$ it shows just difference between 1450-1200= 250$ as total which is wrong. How this can be sorted? Without that, code is kind a not valid.
Thanks. I’m just trying to help the community.
Hey Arven, thanks for that 🙂 The old order has been paid e.g. $20, so the new edited order has a $20 credit and therefore starts at -$20 total. If people confirm the same products, total will be $0 as they’ve already paid.
In your scenario, you would need to programmatically refund the old order, and start afresh with total = $0 and products automatically added to cart. Sorry but this is custom work and can’t help here in the comments. Thanks!
Thank you
You’re welcome 🙂
Hi,
Can u please update a snippet just to allow customer to send request for Cancellation request for a particular time window from order time (Say 120 Minutes) . I see Cancel button request in photo.
Thanks
Hey Kumar, thanks so much for your comment! Yes, this is possible – but unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding! ~R