Manually Update WooCommerce Product Inventory
WordpressCode SnippetsWooCommerce
For 302 West, we needed to have the option to purchase a single cigar or a box of twenty on the same product using the same inventory. We tried to manually subtract 20 from the inventory when a box of twenty was purchased. It worked for the most part, except for 2 problems:
1. It didn't handle the on-hold status correctly. Normally, the inventory would not change when going from "processing" to "on-hold", but with our code it would replace the stock minus one, even though it didn't really seem like our code was running because xdebug wouldn't break. Could not figure out what was wrong or how to fix it.
2. We didn't make it far enough to make sure a user couldn't purchase a box if there were less than 20 in the inventory. It's probably possible, but we decided to go the plugin route instead of spending more time on this.
// Cigar Products come in singles or a box of 20.
// We need to adjust the quantity in WooCommerce orders based on the selection.
// The meta data variable comes from the product attribute, and we are using it to check for the cigar selection.
// When an order is placed, the quantity is adjusted based on the selection.
function rwm_woocommerce_adjust_qty($meta_data)
{
xdebug_break();
// Loop through each meta data
foreach ($meta_data as $meta) {
// Only check for the cigar-qty key
if ($meta->key === 'cigar-qty') {
// Return correct number based on the attribute value
return match ($meta->value) {
'Single' => 1,
'Box of 20' => 20,
default => 1, // Fallback to 1 if no match
};
}
}
// Fallback to 1 if no cigar-qty found
return 1;
}
// Runs when stock quantity changes
// Returns correct number to change by
function rwm_woocommerce_change_qty($qty, $order, $item)
{
xdebug_break();
if ($order->get_status() === 'on-hold') return 0;
// Get the meta data from the product attributes
$meta_data = $item->get_formatted_meta_data('_', true);
// Returns the amount purchased based on the cigar quantity selection
$adjustment = rwm_woocommerce_adjust_qty($meta_data);
// Mulitply the adjustment by the quantity purchased
$qty = $adjustment * absint($qty);
return $qty;
}
add_filter('woocommerce_order_item_quantity', 'rwm_woocommerce_change_qty', 10, 3);
// Manually adjust stock when an order is refunded
function rwm_woocommerce_refund_qty($order_id, $refund_id)
{
xdebug_break();
if ($order->get_status() === 'on-hold') return 0;
$order = wc_get_order($order_id);
// Get all items in the order
$items = $order->get_items();
// Loop through each item
foreach ($items as $item) {
$product = $item->get_product();
// Skip if product doesn't exist or if product is not managing stock
if (! $product || ! $product->managing_stock()) {
continue;
}
// Get the quantity of items refunded
$refunded_qty = $item->get_quantity();
// Adjust the quantity based on the cigar selection
$qty = rwm_woocommerce_change_qty($refunded_qty, $order, $item);
// Manually update stock
wc_update_product_stock($product, $qty, 'increase');
}
}
add_action('woocommerce_order_refunded', 'rwm_woocommerce_refund_qty', 10, 2);