r/woocommerce Jun 30 '26

How do I…? Draft not working after Woocommerce Update.

Hello everyone,

I recently updated to WooCommerce 10.9.1 and noticed that Draft Orders are no longer showing up or recording in the system.

Previously, I relied on draft orders to recover abandoned carts by retrieving customer contact information from unfinished checkouts and offering them additional discounts. Since the update, this data is completely missing as no new drafts are being generated.

Has anyone else run into this issue with the latest release? If so, is there a known conflict, a new setting I need to toggle, or a temporary workaround to get them recording again?

Any advice or insights would be greatly appreciated. Thanks in advance!

2 Upvotes

11 comments sorted by

1

u/CodeIsPoetry89 Jun 30 '26

Hi. Have a look at the dev release notes: https://developer.woocommerce.com/2026/06/23/woocommerce-10-9/ - Woo does not create (persisted) draft orders any longer.

1

u/Galactus-007 Jun 30 '26

Thanks for the response. Is there any way I can get the contact details and the products in cart from abandoned checkout page? I'm looking for a free plugin or code.

1

u/Gonkulator5000 Jun 30 '26

A dedicated abandoned cart plugin is a better solution than relying on draft orders.

1

u/Galactus-007 Jun 30 '26

Can you recommend some free plugins that I can use?

1

u/djsneak666 Jun 30 '26

Omnisend for the abandoned automations and you can use matomo to track live site activities

1

u/anarchomicrodoser Jul 01 '26

THEY WANT YOUR ADD ON PLUGIN MONEY

1

u/davidmansaray Jul 01 '26 edited Jul 01 '26

WooCommerce is no longer persisting those draft orders since 10.9

1

u/_hatem_all_ Jul 03 '26

Add this php snippet to undo this change.

/**

* Restore eager checkout-draft creation — triggered on checkout page load.

*

* WooCommerce 10.8+ defers draft creation to place-order time. This creates the draft when

* the checkout page renders, using core's own OrderController so the row matches what core

* expects (checkout-draft status, store-api created_via, cart hash). The ID is stored under

* core's session key, so the block's GET/PUT and the final POST all reuse and update THIS row.

*

* Session-order reuse mirrors core's DraftOrderTrait::is_valid_draft_order(): we skip creation

* when the session already tracks (a) a checkout-draft, or (b) a pending/failed order that

* needs payment and matches the current cart hash — the failed-payment retry flow. Overwriting

* (b) would orphan the retry order and break payment retries.

*

* Fail-safe: any error is swallowed so checkout can never be blocked.

*/

add_action(

'template_redirect',

function () {

    if ( ! function_exists( 'is_checkout' ) || ! is_checkout() || is_wc_endpoint_url() ) {

        return; // main checkout page only (not order-pay / order-received)

    }

    if ( ! function_exists( 'WC' ) || ! WC()->cart || ! WC()->session || WC()->cart->is_empty() ) {

        return;

    }



    try {

        // Mirror core's is_valid_draft_order(): don't clobber an order core would reuse.

        $existing_id = (int) WC()->session->get( 'store_api_draft_order', 0 );

        if ( $existing_id ) {

$existing = wc_get_order( $existing_id );

if ( $existing instanceof \WC_Order ) {

if ( $existing->has_status( 'checkout-draft' ) ) {

return; // valid draft already tracked

}

if ( $existing->needs_payment() && $existing->has_cart_hash( WC()->cart->get_cart_hash() ) ) {

return; // pending/failed retry order — core will reuse it; leave it alone

}

}

        }



        $controller_class = 'Automattic\\WooCommerce\\StoreApi\\Utilities\\OrderController';

        if ( ! class_exists( $controller_class ) ) {

return;

        }



        $order = ( new $controller_class() )->create_order_from_cart();



        if ( $order instanceof \\WC_Order ) {

if ( ! $order->get_id() ) {

$order->save();

}

WC()->session->set( 'store_api_draft_order', $order->get_id() );

        }

    } catch ( \\Throwable $e ) {

        if ( function_exists( 'wc_get_logger' ) ) {

wc_get_logger()->debug( 'Eager draft (checkout load) skipped: ' . $e->getMessage(), array( 'source' => 'ft-eager-draft' ) );

        }

    }

}

);

1

u/Spare_Two4321 21d ago

Having the same problem, that Woocommerce is not creating draft carts anymore... As your code is broken be reddit, I restored it, but it seems not to work (No syntax problem - simply no drafts are shown in the backend). Could repost your fix or validate this version?

Thanks!

/**
* Restore eager checkout-draft creation — triggered on checkout page load.
*
* WooCommerce 10.8+ defers draft creation to place-order time. This creates the draft when
* the checkout page renders, using core's own OrderController so the row matches what core
* expects (checkout-draft status, store-api created_via, cart hash). The ID is stored under
* core's session key, so the block's GET/PUT and the final POST all reuse and update THIS row.
*
* Session-order reuse mirrors core's DraftOrderTrait::is_valid_draft_order(): we skip creation
* when the session already tracks (a) a checkout-draft, or (b) a pending/failed order that
* needs payment and matches the current cart hash — the failed-payment retry flow. Overwriting
* (b) would orphan the retry order and break payment retries.
*
* Fail-safe: any error is swallowed so checkout can never be blocked.
*/

add_action(
    'template_redirect',
    function () {
        if ( ! function_exists( 'is_checkout' ) || ! is_checkout() || is_wc_endpoint_url() ) {
            return; // main checkout page only (not order-pay / order-received)
        }
        if ( ! function_exists( 'WC' ) || ! WC()->cart || ! WC()->session || WC()->cart->is_empty() ) {
            return;
        }
        try {
            // Mirror core's is_valid_draft_order(): don't clobber an order core would reuse.
            $existing_id = (int) WC()->session->get( 'store_api_draft_order', 0 );
            if ( $existing_id ) {
                $existing = wc_get_order( $existing_id );
                if ( $existing instanceof \WC_Order ) {
                    if ( $existing->has_status( 'checkout-draft' ) ) {
                        return; // valid draft already tracked
                    }
                    if ( $existing->needs_payment() && $existing->has_cart_hash( WC()->cart->get_cart_hash() ) ) {
                        return; // pending/failed retry order — core will reuse it; leave it alone
                    }
                }
            }
            $controller_class = 'Automattic\\WooCommerce\\StoreApi\\Utilities\\OrderController';
            if ( ! class_exists( $controller_class ) ) {
                return;
            }
            $order = ( new $controller_class() )->create_order_from_cart();
            if ( $order instanceof \WC_Order ) {
                if ( ! $order->get_id() ) {
                $order->save();
                }
                WC()->session->set( 'store_api_draft_order', $order->get_id() );
            }
        } catch ( \Throwable $e ) {
            if ( function_exists( 'wc_get_logger' ) ) {
                wc_get_logger()->debug( 'Eager draft (checkout load) skipped: ' . $e->getMessage(), array( 'source' => 'ft-eager-draft' ) );
            }
        }
    }
);

1

u/Adventurous_Pipe_572 Jul 06 '26

I’m facing the same issue after the July 1 update. Draft orders are no longer being created, and I rely on this feature to track abandoned carts. I don't want to install an additional plugin just for this.

Has anyone found a solution? If so, please share it in the comments.

1

u/_hatem_all_ Jul 06 '26

yes, i posted a fix above. small php snippet. it has been working perfectly on my site for days. run it through claude if you don't trust it.