One-click reorder is the single highest-impact feature you can add for repeat customers. A buyer clicks one button, their previous order loads into the cart, and they're at checkout in seconds.
The concept is simple. The implementation requires handling a surprising number of edge cases. This guide walks through the technical details — from querying order history to populating the cart to handling the real-world messiness of price changes, stock issues, and discontinued products.
Architecture Overview
One-click reorder has three components:
- Order history display — showing past orders with reorder buttons
- Cart population — taking products from a past order and adding them to the current cart
- Conflict resolution — handling price changes, stock issues, and missing products
The flow:
User clicks "Reorder" → Fetch order items → Validate each item →
Add valid items to cart → Show conflicts → Redirect to cart page
Let's build each piece.
Step 1: Querying Order History
WooCommerce stores orders as custom post types (or in the High-Performance Order Storage tables in newer versions). To display reorderable past orders:
Using WooCommerce Order API
The WooCommerce REST API provides order data, but for frontend reorder, you'll typically use WooCommerce's internal functions:
$customer_orders = wc_get_orders(array(
'customer_id' => get_current_user_id(),
'status' => array('wc-completed', 'wc-processing'),
'limit' => 10,
'orderby' => 'date',
'order' => 'DESC',
));
Filter for completed/processing orders only — you don't want to show cancelled or refunded orders as reorder options.
Displaying Order Items
For each order, extract the line items:
foreach ($order->get_items() as $item_id => $item) {
$product_id = $item->get_product_id();
$variation_id = $item->get_variation_id();
$quantity = $item->get_quantity();
$product = $item->get_product();
$name = $item->get_name();
$thumbnail = get_the_post_thumbnail_url($product_id, 'thumbnail');
}
Display this data in a user-friendly format: product thumbnail, name, quantity, and current price (not historical price — more on this below).
Step 2: Cart Pre-Population
When the user clicks "Reorder," you need to add all items from the past order to the current cart.
Basic Implementation
The simplest approach — a form submission or AJAX call that triggers:
function handle_reorder($order_id) {
$order = wc_get_order($order_id);
// Security check: order belongs to current user
if ($order->get_customer_id() !== get_current_user_id()) {
return new WP_Error('unauthorized', 'This order does not belong to you.');
}
$results = array('added' => [], 'failed' => []);
foreach ($order->get_items() as $item) {
$product_id = $item->get_product_id();
$variation_id = $item->get_variation_id();
$quantity = $item->get_quantity();
$added = WC()->cart->add_to_cart(
$product_id,
$quantity,
$variation_id,
$variation_id ? $item->get_meta_data() : array()
);
if ($added) {
$results['added'][] = $item->get_name();
} else {
$results['failed'][] = $item->get_name();
}
}
return $results;
}
AJAX Implementation
For a smoother UX, implement via AJAX so the page doesn't reload:
jQuery('.reorder-button').on('click', function(e) {
e.preventDefault();
var orderId = jQuery(this).data('order-id');
jQuery.ajax({
url: wc_params.ajax_url,
type: 'POST',
data: {
action: 'handle_reorder',
order_id: orderId,
nonce: wc_params.reorder_nonce
},
success: function(response) {
if (response.success) {
// Show results and redirect to cart
window.location.href = wc_get_cart_url();
}
}
});
});
Register the AJAX handler on the server side with proper nonce verification.
Cart Clearing Decision
Important UX question: should clicking "Reorder" clear the existing cart first?
Option A: Clear and replace. The cart is emptied and filled with the reorder items. Clean and predictable, but loses anything the user had in their cart.
Option B: Merge. Reorder items are added to whatever's already in the cart. Preserves existing cart contents but can lead to duplicate items.
Option C: Ask. "You have items in your cart. Replace with this order or add to existing cart?" Most user-friendly but adds a step.
For most stores, Option C is best. If the cart is empty, skip the prompt and just add.
Step 3: Handling Edge Cases
This is where most reorder implementations fall short. The happy path is easy — the hard part is everything that can go wrong.
Price Changes
Products ordered 3 months ago may have different prices today. Always use current prices, not historical.
But notify the user about significant changes:
$original_price = $item->get_total() / $item->get_quantity();
$current_price = $product->get_price();
$change_pct = (($current_price - $original_price) / $original_price) * 100;
if (abs($change_pct) > 10) {
$results['price_changes'][] = array(
'name' => $item->get_name(),
'old_price' => $original_price,
'new_price' => $current_price,
'change_percent' => round($change_pct, 1)
);
}
Display: "2 items have changed price since your last order: Protein Powder ($39.99 → $42.99), Fish Oil ($19.99 → $17.99)."
Out-of-Stock Products
Check stock before adding to cart. For out-of-stock items:
- Skip them silently? No — the user expects those items.
- Show a clear notice: "Whey Protein Chocolate is currently out of stock."
- Better: suggest alternatives. "Whey Protein Chocolate is out of stock. Try Whey Protein Vanilla?"
For partial stock (requested 5, only 3 available): add the available quantity and notify.
Discontinued Products
Products get deleted, hidden, or moved to draft. The reorder system needs to handle this:
$product = wc_get_product($product_id);
if (!$product || !$product->exists()) {
$results['discontinued'][] = $item->get_name();
continue;
}
if ($product->get_status() !== 'publish') {
$results['discontinued'][] = $item->get_name();
continue;
}
For discontinued items, suggest similar products based on category or attributes.
Variation Changes
Product variations can be added or removed between orders. A buyer's previous order included "Size: Large, Color: Blue" but that variation no longer exists.
Validate the specific variation, not just the parent product:
if ($variation_id) {
$variation = wc_get_product($variation_id);
if (!$variation || !$variation->is_purchasable()) {
$results['variation_changed'][] = array(
'name' => $item->get_name(),
'parent' => $product_id,
'message' => 'This specific variant is no longer available.'
);
continue;
}
}
Minimum/Maximum Quantities
If you've added minimum order quantities since the last purchase, the reorder might violate them. Check cart-level and product-level quantity restrictions.
Building the Results Screen
After processing the reorder, show a clear summary:
Success section:
- "12 items added to your cart" (with product list)
Warnings section:
- "2 items have changed price" (with old/new prices)
Failures section:
- "1 item is out of stock" (with alternatives)
- "1 item has been discontinued" (with suggestions)
Action buttons:
- "Go to Cart" (primary)
- "Continue Shopping" (secondary)
This transparency builds trust. Silent failures (items quietly dropped from the reorder) erode trust.
Partial Reorder: Item-Level Selection
Full-order reorder is great, but sometimes buyers only want specific items. Implement item-level selection:
- Display all items from the past order with checkboxes
- Pre-check all items by default
- Let the buyer uncheck items they don't want
- "Reorder Selected" button processes only checked items
This handles the common case: "I want my usual order minus the protein bars."
Even better: remember which items the buyer typically deselects and adjust defaults over time.
Subscription-Like Behavior Without Subscriptions
Full subscription systems (WooCommerce Subscriptions) are powerful but heavy. One-click reorder can provide subscription-like convenience without the commitment:
Scheduled reminders. Analyze order frequency and send timed emails: "It's been 28 days since your last order. Reorder now?" Include a direct reorder link.
Calendar integration. Let buyers set a reminder in their calendar. "Remind me to reorder in 4 weeks."
Auto-populated cart on login. When a repeat buyer logs in close to their typical reorder date, pre-populate the cart with their usual order. Show it as a suggestion, not a forced action.
"Make this recurring" option. After a reorder, offer: "Want to make this a recurring order? We'll remind you every [X] days." This captures subscription intent without requiring a full subscription plugin.
These features provide most of the convenience of subscriptions while keeping the buyer in control of each individual order. Many buyers prefer this — they want predictability without commitment.
Performance Considerations
Cart Population Speed
Adding 30 items to the cart one by one triggers 30 woocommerce_add_to_cart hooks. If you have plugins attached to that hook (stock checks, analytics, bundle validation), this gets slow.
Optimization approaches:
- Batch cart operations. Temporarily unhook heavy processing, add all items, then rehook and run validation once.
- Async processing. Add items server-side and update the cart session, then refresh the client.
- Cart fragment caching. Don't refresh cart fragments after each item — wait until all items are added.
Order History Caching
Querying order history on every page load is expensive. Cache the last N orders for each user and invalidate when a new order is placed.
Plugin Options
If you'd rather not build custom:
YITH WooCommerce Order Again — adds "Order Again" buttons to the My Account orders page. Basic but functional.
WooCommerce Order Again Button — similar, with some additional configuration options.
Metorik — analytics platform that includes reorder functionality and automated reorder emails.
List AI — takes reordering further with AI-powered cart filling. Buyers can type "reorder my usual" or combine past orders with new items via natural language.
Measuring Success
Key metrics for your reorder implementation:
- Reorder adoption rate — % of repeat customers who use the reorder button vs. manual cart building
- Time to checkout (reorder) — should be under 60 seconds for a clean reorder
- Conflict resolution rate — % of reorders that encounter issues (stock, price, discontinued). Lower is better.
- Post-reorder modifications — what % of reorders are modified after loading. High modification rates might indicate the wrong order is being suggested.
- Repeat purchase frequency — the ultimate metric. If reorder is easier, buyers should come back more often.
Security Considerations
Don't overlook security in your reorder implementation:
- Verify order ownership. Always check that the order belongs to the current user. Never reorder someone else's order.
- Nonce verification. All reorder AJAX calls must include and verify nonces.
- Rate limiting. Prevent abuse — a user shouldn't be able to trigger hundreds of reorders per minute.
- Input sanitization. If accepting order IDs from the frontend, validate they're integers and exist.
The Big Picture
One-click reorder isn't just a convenience feature — it's a retention strategy. Every friction point in the repeat ordering process is an opportunity for the customer to defect. Every click they don't have to make is a reason to stay.
Amazon's "Buy Again" section is one of their highest-converting features. Subscription services like Chewy make reordering so easy that customers don't even consider alternatives. You can build the same retention dynamics on WooCommerce.
The technical implementation is straightforward. The edge cases require care. And the business impact — in repeat purchase rate, customer lifetime value, and loyalty — is substantial.
Build the reorder button. Handle the edge cases. Watch your repeat customers come back faster.
List AI combines one-click reorder with AI cart filling. Buyers type "my usual order plus bananas and yogurt" and get a pre-filled cart in seconds. See it in action.