Create a WooCommerce Order Directly from the Cart Page, Skipping Checkout

Most WooCommerce workflows take the customer through a separate Checkout page to collect billing details. Sometimes, though — for example in a B2B context where orders go through a quote/approval process — you may want the customer to submit an order directly from the Cart page. This article shows one approach: using Contact Form 7 to collect details on the Cart page and programmatically creating a WooCommerce order via wc_create_order() on successful form submission.

Problem: A sales team needs to collect customer information via a Contact Form 7 form and automatically create a WooCommerce order from the current cart — bypassing the standard multi-step checkout.

Solution: Submit a CF7 form with a hidden field containing serialised cart data, then use the wpcf7_mail_sent hook to call wc_create_order(), add products with $order->add_product(), set billing details, and finalise with $order->calculate_totals() and $order->save().

Step 1. Create a Contact Form 7 form with a hidden field [hidden order-info] and add its shortcode to your custom cart page template (cart.php).

Step 2. On form submit, collect product IDs and quantities from the cart table and write them to the hidden field as JSON:

// Collect cart items and store them in the hidden CF7 field before submission
document.addEventListener( 'wpcf7submit', function () {
    var orderInfo = {};
    document.querySelectorAll( '.woocommerce-cart-form tr[data-id]' ).forEach( function ( row ) {
        var id  = row.dataset.id;
        var qty = row.querySelector( '.qty' );
        if ( id && qty ) {
            orderInfo[ id ] = qty.value;
        }
    } );
    var hiddenField = document.querySelector( '.wpcf7-form input[name*="order-info"]' );
    if ( hiddenField ) {
        hiddenField.value = JSON.stringify( orderInfo );
    }
}, false );

Step 3. Handle the form submission on the server side in functions.php. Validate and sanitise the cart data, create the order, and empty the cart on success:

<?php
add_action( 'wpcf7_mail_sent', function ( $cf7 ) {
    $submission = WPCF7_Submission::get_instance();
    if ( ! $submission ) {
        return;
    }

    $posted_data = $submission->get_posted_data();
    $raw_items   = json_decode( stripslashes( $posted_data['order-info'] ?? '' ), true );

    if ( ! is_array( $raw_items ) ) {
        return;
    }

    // Sanitise: both key (product ID) and value (qty) must be positive integers
    $cart_items = [];
    foreach ( $raw_items as $product_id => $qty ) {
        $pid = absint( $product_id );
        $qty = absint( $qty );
        if ( $pid > 0 && $qty > 0 ) {
            $cart_items[ $pid ] = $qty;
        }
    }

    if ( empty( $cart_items ) ) {
        return;
    }

    $address = [
        'first_name' => sanitize_text_field( $posted_data['customer-name'] ?? '' ),
        'last_name'  => '',
        'email'      => sanitize_email( $posted_data['customer-email'] ?? '' ),
        'phone'      => sanitize_text_field( $posted_data['customer-phone'] ?? '' ),
        'address_1'  => sanitize_text_field( $posted_data['address'] ?? '' ),
    ];

    $order = wc_create_order();

    foreach ( $cart_items as $product_id => $qty ) {
        $order->add_product( wc_get_product( $product_id ), $qty );
    }

    $order->set_address( $address, 'billing' );

    $payment_gateways = WC()->payment_gateways->payment_gateways();
    $order->set_payment_method( $payment_gateways['cod'] );
    $order->calculate_totals();
    $order->update_status( 'processing', 'Order placed via cart form.', true );
    $order->save();

    WC()->cart->empty_cart();
} );

Step 4. Optionally hide the cart table after a successful submission to give the customer a clean confirmation state:

<?php
add_action( 'wp_footer', 'hide_cart_after_order_form_success', 99 );

function hide_cart_after_order_form_success() {
    if ( ! is_cart() ) {
        return;
    }
    ?>
    <script>
        document.addEventListener( 'wpcf7mailsent', function () {
            var cartForm = document.getElementById( 'woocommerce-cart-form' );
            if ( cartForm ) {
                cartForm.style.display = 'none';
            }
        }, false );
    </script>
    <?php
}

NOTE: This approach bypasses the standard WooCommerce Checkout flow, including payment gateway screens. It works best for cash-on-delivery or invoice-based ordering where payment is handled offline. If you need online payment, this pattern requires significant additional work to integrate with a payment gateway.