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!

Displaying an “Edit Order” button for Processing Orders only – WooCommerce

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        Get CustomizeWoo.com FREE
 * @sourcecode    https://businessbloomer.com/?p=91893
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 4.1
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
 
// ----------------
// 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 );
    }
}
Share:

Leave a Reply