Skip to content

Instantly share code, notes, and snippets.

@vapvarun
Created February 24, 2026 19:35
Show Gist options
  • Select an option

  • Save vapvarun/b954bce89fbd181cd21e93092d6d7163 to your computer and use it in GitHub Desktop.

Select an option

Save vapvarun/b954bce89fbd181cd21e93092d6d7163 to your computer and use it in GitHub Desktop.
WooCommerce Upsell and Cross-Sell: Complete Guide (woosellservices.com)
<?php
/**
* Programmatically set upsell products for a WooCommerce product.
*
* WooCommerce stores upsell product IDs in post meta. This
* function demonstrates how to set upsells via code, which
* is useful when migrating data, syncing from an ERP, or
* building automated product recommendation logic.
*
* @param int $product_id The product to add upsells to.
* @param array $upsell_ids Array of product IDs to upsell.
*/
function woosell_set_upsell_products( $product_id, $upsell_ids ) {
// Load the WooCommerce product object
$product = wc_get_product( $product_id );
if ( ! $product ) {
return new WP_Error( 'invalid_product', 'Product not found: ' . $product_id );
}
// Validate that all upsell IDs are real published products
$valid_ids = array();
foreach ( $upsell_ids as $id ) {
$upsell_product = wc_get_product( $id );
if ( $upsell_product && 'publish' === $upsell_product->get_status() ) {
$valid_ids[] = $id;
}
}
// Set the upsell IDs and save the product
// WooCommerce displays these on the single product page
$product->set_upsell_ids( $valid_ids );
$product->save();
return count( $valid_ids ) . ' upsell products set for ' . $product->get_name();
}
<?php
/**
* Customize WooCommerce cross-sell display on the cart page.
*
* By default, WooCommerce shows cross-sells below the cart
* table. This function controls how many cross-sells appear
* and adds custom ordering logic to prioritize products with
* the highest conversion potential (based on sales data).
*
* @param array $cross_sells Array of cross-sell product IDs from cart items.
* @return array Filtered and prioritized cross-sell product IDs.
*/
function woosell_prioritize_cross_sells( $cross_sells ) {
if ( empty( $cross_sells ) ) {
return $cross_sells;
}
// Score each cross-sell product by total sales count
// Products that sell well are more likely to convert
$scored = array();
foreach ( $cross_sells as $product_id ) {
$product = wc_get_product( $product_id );
if ( $product ) {
$scored[ $product_id ] = $product->get_total_sales();
}
}
// Sort by sales descending so best sellers appear first
arsort( $scored );
// Return only top 4 cross-sell products to avoid clutter
return array_slice( array_keys( $scored ), 0, 4 );
}
add_filter( 'woocommerce_cart_crosssell_ids', 'woosell_prioritize_cross_sells' );
/**
* Change the number of cross-sell columns displayed on cart page.
* Default is 2 columns; 4 columns works better for visual products.
*/
add_filter( 'woocommerce_cross_sells_columns', function() {
return 4;
});
<?php
/**
* Add a one-click order bump above the Place Order button.
*
* Displays a highlighted product offer that customers can
* add to their cart with a single checkbox click during
* checkout. This technique typically converts at 5-15%
* and significantly increases average order value.
*
* @since 1.0.0
*/
// Define the bump product ID and discount percentage
define( 'WOOSELL_BUMP_PRODUCT_ID', 123 );
define( 'WOOSELL_BUMP_DISCOUNT', 30 );
/**
* Display the order bump offer box at checkout.
* Hooked just before the payment section for maximum visibility.
*/
function woosell_display_order_bump() {
$product = wc_get_product( WOOSELL_BUMP_PRODUCT_ID );
if ( ! $product || ! $product->is_purchasable() ) {
return;
}
// Don't show if product is already in cart
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( $cart_item['product_id'] === WOOSELL_BUMP_PRODUCT_ID ) {
return;
}
}
$regular_price = $product->get_regular_price();
$bump_price = $regular_price * ( 1 - WOOSELL_BUMP_DISCOUNT / 100 );
// Render the order bump HTML with inline styles
printf(
'<div id="woosell-order-bump" style="border:2px dashed #f0c14b;background:#fffbf0;padding:20px;margin:20px 0;border-radius:8px;">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;font-size:16px;">
<input type="checkbox" name="woosell_add_bump" value="1" style="width:20px;height:20px;" />
<span>
<strong>One-Time Offer:</strong> Add %s for just %s
<span style="text-decoration:line-through;color:#999;">%s</span>
<span style="color:#e63946;font-weight:bold;">(%d%% OFF)</span>
</span>
</label>
<p style="margin:8px 0 0 32px;color:#666;font-size:14px;">%s</p>
</div>',
esc_html( $product->get_name() ),
wc_price( $bump_price ),
wc_price( $regular_price ),
WOOSELL_BUMP_DISCOUNT,
esc_html( $product->get_short_description() )
);
}
add_action( 'woocommerce_review_order_before_payment', 'woosell_display_order_bump' );
/**
* Process the order bump: add product to cart if checkbox was checked.
* Applies the discount as a custom fee so it shows in order totals.
*/
function woosell_process_order_bump() {
if ( ! isset( $_POST['woosell_add_bump'] ) ) {
return;
}
$product = wc_get_product( WOOSELL_BUMP_PRODUCT_ID );
if ( ! $product ) {
return;
}
// Add to cart and apply discount as negative fee
WC()->cart->add_to_cart( WOOSELL_BUMP_PRODUCT_ID );
$discount = $product->get_regular_price() * ( WOOSELL_BUMP_DISCOUNT / 100 );
WC()->cart->add_fee(
sprintf( '%s - %d%% checkout discount', $product->get_name(), WOOSELL_BUMP_DISCOUNT ),
-$discount
);
}
add_action( 'woocommerce_checkout_update_order_review', 'woosell_process_order_bump' );
<?php
/**
* Display a post-purchase upsell offer on the thank-you page.
*
* After completing a purchase, customers are in a buying
* mindset. Showing a relevant product offer on the order
* confirmation page converts at 3-8% according to industry
* benchmarks. This adds the product directly to a new cart
* for one-click purchase.
*
* @param int $order_id The completed order ID.
*/
function woosell_thankyou_upsell( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
// Find a relevant upsell based on what was just purchased
$upsell_id = null;
foreach ( $order->get_items() as $item ) {
$product = $item->get_product();
$upsell_ids = $product->get_upsell_ids();
if ( ! empty( $upsell_ids ) ) {
// Pick the first upsell that wasn't in this order
$ordered_ids = wp_list_pluck( $order->get_items(), 'product_id' );
$available = array_diff( $upsell_ids, $ordered_ids );
if ( ! empty( $available ) ) {
$upsell_id = reset( $available );
break;
}
}
}
if ( ! $upsell_id ) {
return;
}
$upsell = wc_get_product( $upsell_id );
if ( ! $upsell || ! $upsell->is_purchasable() ) {
return;
}
// Build the add-to-cart URL for one-click purchase
$add_url = add_query_arg(
array(
'add-to-cart' => $upsell_id,
'quantity' => 1,
),
wc_get_checkout_url()
);
// Display the upsell offer
printf(
'<div style="background:#f8f9fa;border:1px solid #dee2e6;border-radius:12px;padding:24px;margin:24px 0;text-align:center;">
<h3 style="margin-top:0;">Complete Your Purchase</h3>
<p>Customers who bought %s also love:</p>
<div style="margin:16px 0;">%s</div>
<h4>%s</h4>
<p style="font-size:24px;font-weight:bold;color:#2d3436;">%s</p>
<a href="%s" style="display:inline-block;background:#0073aa;color:#fff;padding:12px 32px;border-radius:6px;text-decoration:none;font-weight:bold;">Add to Cart &amp; Checkout</a>
</div>',
esc_html( $order->get_items() ? current( $order->get_items() )->get_name() : '' ),
$upsell->get_image( 'woocommerce_thumbnail' ),
esc_html( $upsell->get_name() ),
$upsell->get_price_html(),
esc_url( $add_url )
);
}
add_action( 'woocommerce_thankyou', 'woosell_thankyou_upsell', 5 );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment