Most supply chain managers I meet treat their SKU data as a pile of unrelated rows. They pay for complex Demand Forecasting models that score each product on its own, then get blindsided when a shock in one category drags another down with it. The model never knew the two were connected.
In more than 14 years of refactoring messy WooCommerce and enterprise backends, the costliest mistake I run into is not bad code. It is a bad data model. Most systems assume a demand spike for SKU-A tells you nothing about SKU-B. If the two share a factory line or a storage bin, that assumption is wrong.
Where the island approach to demand forecasting fails
Traditional Demand Forecasting leans on time-series analysis. That catches seasonality. It says nothing about structural dependencies between products. I wrote about Why GNNs Win at Demand Forecasting earlier, and Heterogeneous Graph Transformers (HGT) are the part I skipped.
Basic Graph Neural Networks (GNNs) such as GraphSAGE treat every connection as equal. To GraphSAGE, a “Shared Warehouse” edge looks the same as a “Product Substitute” edge, and that flattening is where operational insight hits a bottleneck. In an FMCG supply chain the two edges mean opposite things. A shared plant carries capacity signals. A product group carries demand transfer.
How HGT gives connections meaning
HGT fixes this by keeping the edge types apart. Instead of one generic aggregation function, it learns a separate mechanism per connection type, and multi-head attention decides which neighbor matters right now, along with which type of neighbor it is.
If you are building the data structure for this in WordPress or WooCommerce, a flat wp_postmeta table will not carry the information. You need typed relationships. Below is the version most of us write first, next to the version an HGT model can actually use.
<?php
/**
* THE NAIVE APPROACH: Flat Metadata
* This makes it impossible for an AI model to distinguish
* between a "Substitute" and a "Shared Factory."
*/
update_post_meta( $sku_id, '_related_skus', [101, 202, 303] );
/**
* THE HGT-READY APPROACH: Typed Edge Relationships
* We define the MEANING of the connection.
*/
function bbioon_register_sku_edge( $from_sku, $to_sku, $edge_type ) {
global $wpdb;
$wpdb->insert(
'wp_sku_graph_edges',
[
'from_sku' => $from_sku,
'to_sku' => $to_sku,
'edge_type' => $edge_type, // 'plant', 'subgroup', 'storage'
]
);
}
What relationship awareness does to the WAPE
On a standard FMCG dataset, moving from a naive baseline to HGT dropped the WAPE (Weighted Absolute Percentage Error) from 0.86 to 0.58, a 32% cut in misallocated demand. The forecasts also arrive earlier. Because the model reads the subgroup structure, it can call a peak before it lands by watching signals in related nodes.
Explainability is what got this shipped. When a planner asks why the forecast dipped, we can point at a trend in a specific storage node or a precursor SKU instead of shrugging at the model. The graph matches how the supply chain actually moves.
If this Demand Forecasting work is eating your dev hours, hand it over. I have been wrestling with WordPress since the 4.x days.
Stop modeling SKUs in isolation
Treating SKUs as independent variables costs accuracy you can measure. If you want production-grade Demand Forecasting, the network structure has to be in the model with the edge types intact. That means storing your catalog as a graph rather than a spreadsheet, which is a data modeling job before it is a machine learning one.