Dark Light

WooCommerce AI Product Recommendations: Personalization Without Third-Party Services

Varun Dubey 11 min read

Every WooCommerce store has a Related Products section. Almost none of them are actually useful. The default block pulls items from the same category and tags, which means a customer buying a $400 camera lens gets recommended a $9 lens cap alongside a camera bag and a tripod, all technically “cameras,” none of them a smart suggestion. This guide is about fixing that. Specifically, it is about building genuine WooCommerce AI recommendations and WooCommerce personalization that run entirely on your own server, with no monthly SaaS fee and no customer data leaving your infrastructure.

The techniques here range from zero-code approaches using existing WooCommerce data to PHP-based implementations using lightweight machine learning libraries. You do not need a data science background. You do need access to your server and a willingness to think about your product catalog as data.

WooCommerce’s built-in related products are similarity-based, not behavior-based. Two products are “related” if they share a category or tag. That logic made sense when ecommerce was new. Today, customers expect the store to know what they actually want, not just what section of the catalog they are browsing.

There is a meaningful difference between:

  • Similarity-based recommendations: “This product is in the same category as what you are looking at.”
  • Behavior-based recommendations: “Customers who bought this also bought these specific other items.”
  • Personalized recommendations: “Based on this customer’s purchase and browsing history, these items are most likely to convert.”

Third-party recommendation engines like Nosto, Barilliance, and LimeSpot deliver the third type, but they do so by sending your customer data to their servers, charging a monthly fee that scales with revenue, and giving you limited control over the algorithm. For stores that want full data ownership, or that find SaaS fees eating into margin, building a self-hosted alternative is a realistic project.

If you want background on what existing AI-powered plugins offer before going the custom route, this overview of AI product recommendations for WooCommerce stores covers the plugin landscape in detail.

The Data You Already Have

WooCommerce AI Product Recommendations

Before writing a single line of code, take stock of what WooCommerce already records. Your wp_woocommerce_order_items table contains every product ID on every order ever placed. That is the foundation for collaborative filtering, the technique behind “customers who bought X also bought Y.”

Here is what WooCommerce stores by default:

Data TypeTable / SourceUseful For
Order line itemswp_woocommerce_order_items + order_itemmetaCo-purchase analysis (“also bought”)
Product viewsWooCommerce sessions / custom trackingView-based recommendations
Customer order historywp_posts (orders) + wp_woocommerce_order_itemsRepeat-purchase prediction
Product attributeswp_terms + wp_term_relationshipsContent-based filtering
Search queriesWooCommerce search logs (if enabled)Intent detection
Cart abandonmentwp_woocommerce_sessionsRecovery-focused recommendations

The order items table is the highest-value data source for most stores. A simple SQL query can tell you which product pairs appear together most frequently in the same order, and that frequency data is the raw material for a “frequently bought together” widget that actually reflects real customer behavior.

Building a Co-Purchase Recommendation Engine in PHP

This is the most practical starting point for most stores. The approach is straightforward: query the orders table to find which product pairs co-occur most often, cache the results, and display them on product pages. No external services, no data transfer, no ongoing fees.

Step 1: Query Co-Purchase Pairs

Add this function to your theme’s functions.php or a custom plugin:

function woosell_get_copurchase_recommendations( $product_id, $limit = 4 ) {
    global $wpdb;

    $cache_key = 'copurchase_' . $product_id . '_' . $limit;
    $cached    = get_transient( $cache_key );

    if ( false !== $cached ) {
        return $cached;
    }

    $results = $wpdb->get_results( $wpdb->prepare(
        "SELECT
            oi2.order_item_id,
            oim2.meta_value AS product_id,
            COUNT(*) AS frequency
        FROM {$wpdb->prefix}woocommerce_order_items oi1
        JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim1
            ON oi1.order_item_id = oim1.order_item_id
            AND oim1.meta_key = '_product_id'
        JOIN {$wpdb->prefix}woocommerce_order_items oi2
            ON oi1.order_id = oi2.order_id
            AND oi1.order_item_id != oi2.order_item_id
        JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim2
            ON oi2.order_item_id = oim2.order_item_id
            AND oim2.meta_key = '_product_id'
        WHERE oim1.meta_value = %d
            AND oim2.meta_value != %d
        GROUP BY oim2.meta_value
        ORDER BY frequency DESC
        LIMIT %d",
        $product_id,
        $product_id,
        $limit
    ) );

    $product_ids = wp_list_pluck( $results, 'product_id' );
    set_transient( $cache_key, $product_ids, 6 * HOUR_IN_SECONDS );

    return $product_ids;
}

This query joins the order items table with itself to find products that appear in the same order as your target product. Results are cached in WordPress transients for 6 hours to avoid running the query on every page load.

Step 2: Display Recommendations

Hook into WooCommerce’s product page output to render your recommendations:

add_action( 'woocommerce_after_single_product_summary', 'woosell_render_recommendations', 25 );

function woosell_render_recommendations() {
    global $product;

    if ( ! $product ) return;

    $product_ids = woosell_get_copurchase_recommendations( $product->get_id() );

    if ( empty( $product_ids ) ) return;

    echo '<section class="woosell-recommendations">';
    echo '<h2>Frequently Bought Together</h2>';

    $args = array(
        'post_type'      => 'product',
        'post__in'       => $product_ids,
        'orderby'        => 'post__in',
        'posts_per_page' => count( $product_ids ),
    );

    $loop = new WP_Query( $args );

    if ( $loop->have_posts() ) {
        echo '<ul class="products">';
        while ( $loop->have_posts() ) {
            $loop->the_post();
            wc_get_template_part( 'content', 'product' );
        }
        echo '</ul>';
    }

    wp_reset_postdata();
    echo '</section>';
}

This renders your data-driven recommendations using WooCommerce’s standard product template, which means they inherit your theme’s styling and respect sale prices, stock status, and add-to-cart logic automatically.

Customer-Level Personalization With Purchase History

Co-purchase analysis gives you good general recommendations. True personalization means knowing what a specific logged-in customer has bought before and recommending based on their individual history. WooCommerce stores this data, you just need to query it differently.

Tracking and using customer analytics data well is the foundation of any personalization effort. The WooCommerce reports and analytics guide explains how to interpret your store data before building on top of it.

function woosell_get_personalized_recommendations( $customer_id, $limit = 4 ) {
    $cache_key = 'personal_recs_' . $customer_id;
    $cached    = get_transient( $cache_key );
    if ( false !== $cached ) return $cached;

    // Get the customer's purchased product IDs
    $orders = wc_get_orders( array(
        'customer_id' => $customer_id,
        'status'      => array( 'completed', 'processing' ),
        'limit'       => 20,
    ) );

    $purchased_ids = array();
    foreach ( $orders as $order ) {
        foreach ( $order->get_items() as $item ) {
            $purchased_ids[] = $item->get_product_id();
        }
    }

    if ( empty( $purchased_ids ) ) return array();

    // Find co-purchases for all their purchased products
    $recommendations = array();
    foreach ( $purchased_ids as $pid ) {
        $related = woosell_get_copurchase_recommendations( $pid, 10 );
        foreach ( $related as $rec_id ) {
            if ( ! in_array( $rec_id, $purchased_ids ) ) {
                $recommendations[ $rec_id ] = ( $recommendations[ $rec_id ] ?? 0 ) + 1;
            }
        }
    }

    arsort( $recommendations );
    $top_ids = array_slice( array_keys( $recommendations ), 0, $limit );

    set_transient( $cache_key, $top_ids, HOUR_IN_SECONDS );
    return $top_ids;
}

This function aggregates co-purchase recommendations across everything the customer has ever bought, removes products they already own, and returns the items that appear most consistently in orders from customers similar to them. It is not neural-network personalization, but for most stores it outperforms the default related products block significantly.

Content-Based Filtering: Recommendations Without Order History

Co-purchase analysis requires transaction data. For new stores, new products, or guest visitors, you need a different approach. Content-based filtering recommends products that are similar to the one currently being viewed, but using more signals than WooCommerce’s default category/tag matching.

The idea is to represent each product as a vector of attributes, then compute similarity scores between products. Attributes you can use:

  • Category (with weighted hierarchy, subcategory match scores higher than top-level category)
  • Tags (exact tag matches score higher than partial overlaps)
  • Price range (products within ±30% price range score higher)
  • Product attributes (color, size, material, especially useful for variable products)
  • Description keyword overlap (TF-IDF style, though simpler approximations work)
SignalWeightRationale
Same sub-category3.0Strong relevance signal
Same parent category1.5Moderate relevance
Shared tag1.0 per tagCumulative, more shared tags = higher score
Price within 30%1.5Customer is in the same budget bracket
Price within 60%0.8Minor price affinity
Same brand attribute2.0Brand loyalty is a strong predictor
Shared product attribute0.5 per matchMaterial, color, etc.

Pre-compute these scores weekly or on product updates, store them in a custom table or post meta, and query them at display time. This gives you fast, accurate recommendations even for guest users and newly listed products.

Displaying Recommendations: Block Patterns and Shortcodes

Once you have the recommendation logic in place, you need to expose it in your theme. There are two practical approaches: a shortcode for Classic themes and page builders, and a block pattern for block-based themes.

Shortcode Implementation

add_shortcode( 'woosell_recommendations', function( $atts ) {
    $atts = shortcode_atts( array(
        'product_id' => get_the_ID(),
        'limit'      => 4,
        'title'      => 'You May Also Like',
    ), $atts );

    $product_ids = woosell_get_copurchase_recommendations(
        intval( $atts['product_id'] ),
        intval( $atts['limit'] )
    );

    if ( empty( $product_ids ) ) return '';

    ob_start();
    echo '<div class="woosell-recs-shortcode">';
    echo '<h3>' . esc_html( $atts['title'] ) . '</h3>';

    foreach ( $product_ids as $pid ) {
        $prod = wc_get_product( $pid );
        if ( ! $prod || ! $prod->is_visible() ) continue;
        // Render product card
        wc_setup_product_data( $pid );
        wc_get_template_part( 'content', 'product' );
    }

    echo '</div>';
    return ob_get_clean();
} );

Use this shortcode anywhere in your content: [woosell_recommendations limit="4" title="Customers Also Bought"]. It works in product descriptions, page content, and widget areas that support shortcodes.

Placement Strategy

Where you display recommendations affects click-through rate significantly. Tested placement options, ranked by typical performance:

  1. After add-to-cart button, high visibility, captures intent at peak moment
  2. After product description, good for considered purchases where customers read content
  3. Cart page sidebar, last upsell opportunity before checkout
  4. Order confirmation page, lower conversion but useful for cross-sell at post-purchase
  5. Shop/category pages, personalized grid based on recent views, lower intent context

Integrating With WooCommerce Loyalty Programs

Recommendations become significantly more powerful when they are connected to your loyalty and retention strategy. Surfacing recommendations like “Buy this to reach Gold status” or “These items earn 3x points this week” combines personalization with incentive in a way that drives both conversion and lifetime value.

The guide to customer loyalty programs for WooCommerce covers which plugins provide programmatic access to points data, which is what you need to combine recommendations with loyalty logic.

A basic pattern for loyalty-aware recommendations:

  1. Get the customer’s current loyalty tier and points balance from your loyalty plugin’s API
  2. Calculate how many points each recommended product would earn
  3. Boost the display score of products that would push the customer to the next tier
  4. Show a contextual label: “Earns 450 points, only 50 away from Gold”

This requires no third-party recommendation engine. It just requires connecting two data sources you already have: your order history and your loyalty plugin’s data.

Performance Optimization and Caching Strategy

Recommendation queries can be expensive if run on every page load. A caching strategy is not optional, it is a prerequisite for production deployment. Here is a layered approach that works at any scale:

LayerMethodTTLUse Case
Database query cacheWordPress Transients API6 hoursPer-product co-purchase pairs
Customer recommendation cacheTransient + user meta1 hourPer-customer personalized list
Pre-computed matrixCustom table or object cache24 hours (cron rebuild)Full-catalog similarity scores
Fragment cacheOutput buffering + transient30 minutesRendered HTML blocks
Redis object cacheRedis/Memcached + WP pluginPersistentHigh-traffic stores (500+ concurrent)

For most stores under 10,000 products and 50,000 orders, transient caching per product ID is sufficient. The query itself takes 50–150ms uncached; with transients it drops to under 1ms. Schedule a WP-Cron job to pre-warm the cache for your top 100 products during off-peak hours.

// Pre-warm cache for top products
add_action( 'woosell_prewarm_recommendations', function() {
    $top_products = wc_get_products( array(
        'limit'   => 100,
        'orderby' => 'total_sales',
        'order'   => 'DESC',
        'status'  => 'publish',
    ) );

    foreach ( $top_products as $product ) {
        delete_transient( 'copurchase_' . $product->get_id() . '_4' );
        woosell_get_copurchase_recommendations( $product->get_id(), 4 );
    }
} );

if ( ! wp_next_scheduled( 'woosell_prewarm_recommendations' ) ) {
    wp_schedule_event( strtotime( 'tomorrow 3am' ), 'daily', 'woosell_prewarm_recommendations' );
}

Measuring Recommendation Effectiveness

Building the system is only half the work. If you cannot measure whether recommendations are actually converting, you cannot improve them. Track these metrics at minimum:

  • Recommendation click-through rate: What percentage of customers who see recommendations click at least one? (Benchmark: 5–15% for well-placed recommendations)
  • Recommendation-to-purchase rate: Of customers who click a recommendation, what percentage complete a purchase of that item?
  • Average order value lift: Do orders that include a recommended item have a higher AOV than those that do not?
  • Items per order: Are customers buying more products per transaction since you added recommendations?

Track recommendation clicks by adding a URL parameter when recommendations are displayed: ?rec_source=copurchase. This lets you filter in Google Analytics or WooCommerce’s built-in reports to isolate recommendation-driven revenue without installing any additional tracking code.

Frequently Asked Questions

Do self-hosted AI recommendations require a machine learning library?

No. The co-purchase approach described in this guide is pure SQL and PHP, no ML library required. True machine learning (collaborative filtering with matrix factorization, neural network-based recommendations) does require libraries like PHP-ML or offloading computation to Python scripts via WP-CLI. But for stores with under 50,000 orders, the SQL-based approach typically delivers comparable recommendation quality to basic ML models, because the limiting factor is data volume, not algorithm sophistication. Start with the SQL approach, measure results, and add ML complexity only if you see diminishing returns.

How many orders do I need before co-purchase recommendations become reliable?

The minimum practical threshold is around 500 completed orders across at least 50 distinct products. Below that, co-purchase data is too sparse to produce meaningful recommendations, you will end up showing the same 2–3 popular products as recommendations for everything. With fewer orders, use content-based filtering (category, tags, price, attributes) instead. Between 500 and 5,000 orders, blend both approaches: use co-purchase data where it exists and fall back to content-based filtering for products with sparse transaction history.

Can I use these recommendations for email marketing without a third-party ESP?

Yes, with some additional work. WooCommerce’s transactional email system (via WC_Email) supports dynamic content hooks. You can call your recommendation functions in email templates to include personalized product sections in order confirmation and abandoned cart emails. The limitation is that email images must be absolute URLs, and you cannot use JavaScript for email rendering, but a static grid of recommended products with product images, names, and prices is entirely achievable. Tools like FluentCRM or AutomateWoo (which run locally) expose hooks that make this even more practical, as they have built-in support for WooCommerce product data in email templates.

Advanced Techniques: Seasonality and Trend Weighting

Static co-purchase data has one significant limitation: it treats an order from three years ago the same as an order from last week. For most product categories, buying patterns change with seasons, trends, and inventory shifts. Adding time-decay weighting to your recommendation algorithm significantly improves relevance without meaningfully increasing complexity.

The simplest time-decay approach assigns a weight to each order based on how recent it is. Orders from the last 30 days get full weight (1.0), orders from 31–90 days get 0.7, orders from 91–180 days get 0.4, and older orders get 0.2. Multiply co-purchase frequency by this weight when computing recommendation scores.

function woosell_time_decay_weight( $order_date_string ) {
    $order_date = new DateTime( $order_date_string );
    $now        = new DateTime();
    $days_ago   = $now->diff( $order_date )->days;

    if ( $days_ago <= 30 )  return 1.0;
    if ( $days_ago <= 90 )  return 0.7;
    if ( $days_ago <= 180 ) return 0.4;
    return 0.2;
}

For seasonal products (holiday decorations, summer gear, back-to-school supplies), you can also boost recommendations for products that have shown increased sales velocity in the current month compared to the rolling 12-month average. This requires tracking sales velocity per product, which WooCommerce's analytics tables already enable with a simple query comparing current-period and prior-period sales counts.

Trend weighting is especially valuable for fashion, home decor, and lifestyle products where what sold well six months ago may no longer be relevant. For commodity products (hardware, office supplies, consumables), trend weighting matters less, the same items tend to be purchased together regardless of when.

A/B Testing Your Recommendation Strategy

No recommendation algorithm is universally optimal across all store types and customer bases. The only way to know which approach works best for your specific store is to test. WordPress does not have built-in A/B testing, but you can implement a lightweight test using user session splitting.

A simple approach: use the last digit of the customer's session ID to split traffic. Sessions ending in 0–4 see co-purchase recommendations; sessions ending in 5–9 see content-based recommendations. Track which group generates higher average order values over a 4-week period using WooCommerce's order notes or a custom meta field.

  • Test duration: Run for at least 4 weeks to capture weekly buying patterns and enough statistical volume
  • Sample size: Need at least 200 conversions per variant for statistical significance at 95% confidence
  • Primary metric: Average order value (not click-through rate, clicks that do not convert are noise)
  • Secondary metrics: Items per order, 30-day repeat purchase rate, recommendation click-through rate

Once you have a winner, do not stop testing. The optimal recommendation strategy for Q4 holiday shopping may be different from what works best in Q2. Build the habit of running at least one recommendation test per quarter to continuously improve performance.

Getting Started Today

Building self-hosted WooCommerce AI recommendations and WooCommerce personalization is not a weekend project if you want the full stack, but the co-purchase engine covered in this guide is a realistic one-to-two day implementation for a developer familiar with WordPress and WooCommerce hooks. The ROI case is straightforward: a 5% increase in items per order on a store doing $50,000/month in revenue is $2,500 in additional monthly revenue, recurring, with no ongoing platform fees.

Start with the SQL co-purchase query. Deploy it to a staging environment, validate the results against your actual order history, and measure click-through rate for two weeks before rolling out to production. The data you already have is likely better than you expect. The recommendations engine is the piece that lets you use it.

If you want to compare what plugins can do versus a custom build before committing to development time, the full AI recommendations plugin overview gives you the feature-by-feature comparison you need to make that decision with data.

Varun Dubey

Shaping Ideas into Digital Reality | Founder @wbcomdesigns | Custom solutions for membership sites, eLearning & communities | #WordPress #BuddyPress