Demand forecasting with graph neural networks in WooCommerce

The usual Demand Forecasting setup in WooCommerce is a rolling window: last month’s sales predict next month’s stock. I have watched that naive approach fail badly in stores carrying 10,000+ SKUs. You end up over-stocked on slow movers and out of your best sellers in the same week, which is about the worst combination available.

Usually the data is fine. The model is the problem, because it assumes each product lives in a vacuum when the supply chain behind it is one connected operation. Getting anywhere with supply chain data science means looking at the network, not only at the rows.

The architecture of networked SKUs

Products in a large WooCommerce catalog share more than a brand name. They share plants, logistics subgroups, sometimes the same storage location. A demand shift in one corner of that network moves things in the other corners. Traditional time-series models never see it, because each SKU is an independent variable to them.

This is what Graph Neural Networks (GNNs), and GraphSAGE in particular, are for. Where the old model reads “Product A sales history,” a GNN reads “Product A sales history + its neighbors’ activity + shared constraints.”

Why traditional forecasting bottlenecks your store

I thought I had seen every way a store can break until a client turned up with 40 active SKUs spread across 9 manufacturing plants. Their forecasting error, measured as WAPE, sat near 86%. Every day went into firefighting and emergency production changes, because the predictive plugin they paid for was mirroring yesterday’s sales back at them.

// The Naive Approach: "Tomorrow = Today" logic
function bbioon_naive_stock_prediction( $product_id ) {
    $yesterday_sales = get_post_meta( $product_id, '_bbioon_daily_sales_total', true );
    // This assumes isolation. It ignores shared plant capacity or category trends.
    return $yesterday_sales; 
}

Implementing graph neural network logic

A production Demand Forecasting model starts with the store represented as a graph: SKUs are the nodes, and the relationships between them, meaning shared attributes, are the edges. Per the official GraphSAGE documentation, that inductive setup lets the model generalize to products added to the graph later.

Spatial encoders then let information travel between connected SKUs. When one product group starts spiking, its neighbors get the signal and can be prepared for a correlated shift. The relationships for that first graph can come straight out of WooCommerce attributes.

<?php
/**
 * Representing the SKU Network in PHP
 * This snippet extracts "Neighbors" based on shared manufacturing plants.
 */
function bbioon_get_sku_neighbors( $product_id ) {
    $plant_id = get_post_meta( $product_id, '_manufacturing_plant', true );
    
    $args = array(
        'post_type'  => 'product',
        'meta_query' => array(
            array(
                'key'     => '_manufacturing_plant',
                'value'   => $plant_id,
                'compare' => '=',
            ),
        ),
        'fields'     => 'ids',
        'exclude'    => array( $product_id ),
    );

    $neighbor_ids = get_posts( $args );
    
    // In a real GNN integration, you would ship this adjacency list
    // to a Python service running MLflow or Torch.
    return $neighbor_ids;
}

Clients who stopped chasing isolated accuracy and started deciding on the network have taken misallocation error from 86% down to roughly 62%. At high volume, those 24 points are the difference between profit and pallets of stock nobody ordered.

If this Demand Forecasting work is eating your dev hours, I can take it on. WordPress has been my day job since the 4.x days.

Heterogeneous transformers come next

GraphSAGE has one blind spot: every relationship counts the same. A shared plant behaves nothing like a shared brand family. Heterogeneous Graph Transformers (HGT) weight the edge types differently, so the forecast responds to structural constraints such as plant capacity or a logistics bottleneck instead of only to sales peaks.

Transients and rolling windows will keep your stock numbers roughly plausible while quietly costing you money. The catalog behaves like a graph whether or not the model treats it as one.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.