9/3/2024
WooCommerce dropshipping — automatic margin sync with your supplier
TL;DR: Per-category margin multiplier + automatic calculation at XML import = zero manual price setting. Changing the margin for the “IP Cameras” category from 1.3x to 1.4x = 1 config entry, and the next import recalculates everything else.
Dropshipping is a model where supplier prices change regularly — new stock, exchange rates, seasonality. If your store has 2,700 products, manually updating prices after every supplier change takes several hours. Automatic sync reduces this to running a cron job.
The problem with manual price management
With a catalog of 2,700 products, changing a pricing strategy — for example raising the margin for the entire “DVR Recorders” category from 30% to 40% — means (in the manual approach): exporting a CSV from WooCommerce, opening it in Excel, filtering by category, applying a formula to the price column, saving, and importing back. The procedure takes 2 hours and is prone to errors: it’s easy to overwrite the wrong column, import an old file, or miss products in subcategories.
The worse scenario: the supplier changes prices weekly. With every change you need to recalculate all products, because your price should be: supplier_price × margin. If you don’t update regularly, you’re selling below margin.
The solution: supplier price is always the source of truth. Margins live in configuration. XML import calculates automatically.
Margin configuration structure
A simple PHP array as a config file:
// config/margins.php
return [
'ip-cameras' => 1.35,
'dome-cameras' => 1.35,
'bullet-cameras' => 1.30,
'dvr-recorders' => 1.40,
'nvr-recorders' => 1.38,
'cctv-accessories' => 1.45,
'power-supplies' => 1.50,
'cabling' => 1.55,
'_default' => 1.30, // fallback for unknown categories
];
Price calculation function:
function calculatePrice(float $supplierPrice, string $categorySlug): float {
$margins = config('margins');
$multiplier = $margins[$categorySlug] ?? $margins['_default'];
return round($supplierPrice * $multiplier, 2);
}
round() to 2 decimal places prevents prices like 149.99999 in the database.
Integration with the XML importer
When parsing the supplier’s XML feed (e.g. Hurton format), for each product:
function importProduct(SimpleXMLElement $node): void {
$supplierPrice = (float) $node->cena_netto;
$categorySlug = sanitizeSlug((string) $node->kategoria);
$finalPrice = calculatePrice($supplierPrice, $categorySlug);
$sku = (string) $node->symbol;
// Check if the product exists
$productId = wc_get_product_id_by_sku($sku);
if ($productId) {
// Update existing
$product = wc_get_product($productId);
$product->set_regular_price($finalPrice);
$product->save();
} else {
// New product
$product = new WC_Product_Simple();
$product->set_sku($sku);
$product->set_name((string) $node->nazwa);
$product->set_regular_price($finalPrice);
// ... other fields
$product->save();
}
}
Importing 2,700 products with proper use of wc_get_product_id_by_sku() (a query on meta_value) takes 3–8 minutes depending on the server. Optimization: batch updates via direct SQL queries on the _regular_price field instead of using the WooCommerce API.
Dynamic margin
A more advanced approach — margin depending on the base product price. Cheap products have low absolute profit at a small margin, so a higher multiplier makes sense:
function calculateDynamicPrice(float $supplierPrice, string $categorySlug): float {
$margins = config('margins');
$baseMultiplier = $margins[$categorySlug] ?? $margins['_default'];
// Correction based on price
if ($supplierPrice < 50) {
$correction = 1.15; // +15% for cheap products
} elseif ($supplierPrice < 200) {
$correction = 1.05; // +5% for mid-range
} else {
$correction = 1.00; // no correction for expensive items
}
return round($supplierPrice * $baseMultiplier * $correction, 2);
}
Effect: a product costing 20 PLN from the supplier with margin 1.35 × 1.15 = 1.5525 = price 31 PLN (absolute margin 11 PLN). The same multiplier for a 1000 PLN product gives a 1350 PLN price (margin 350 PLN) — no correction needed there.
Margin monitoring
WooCommerce hook to detect sales below the margin threshold:
add_action('woocommerce_order_item_meta_end', function($item_id, $item, $order) {
$product = $item->get_product();
$salePrice = (float) $item->get_total() / $item->get_quantity();
$costMeta = get_post_meta($product->get_id(), '_supplier_price', true);
$supplierCost = (float) $costMeta;
if ($supplierCost > 0) {
$margin = ($salePrice - $supplierCost) / $salePrice;
if ($margin < 0.15) {
// Alert: margin below 15%
wp_mail(
'admin@yourshop.com',
'Alert: low margin',
"Product {$product->get_name()} sold with margin " . round($margin * 100) . "%"
);
}
}
}, 10, 3);
It’s also worth saving the supplier price as a _supplier_price meta field at every import. That gives you a history of supplier price changes and lets you analyze trends.
Summary
Automatic margin sync is essential for dropshipping with more than a few hundred products. Configuration as a PHP array, calculation at import, alert monitoring — a system that takes a week to build once and saves hours every week. With a store of 2,700 products and weekly supplier price changes — it’s a necessity.