Automattic\WooCommerce\Checkout\Helpers
ReserveStock::reserve_stock_for_product
Reserve stock for a product by inserting rows into the DB.
Method of the class: ReserveStock{}
No Hooks.
Returns
null. Nothing (null).
Usage
// private - for code of main (parent) class only $result = $this->reserve_stock_for_product( $product_id, $stock_quantity, $order, $minutes );
- $product_id(int) (required)
- Product ID which is having stock reserved.
- $stock_quantity(int) (required)
- Stock amount to reserve.
- $order(WC_Order) (required)
- Order object which contains the product.
- $minutes(int) (required)
- How long to reserve stock in minutes.
ReserveStock::reserve_stock_for_product() ReserveStock::reserve stock for product code WC 10.9.4
private function reserve_stock_for_product( $product_id, $stock_quantity, $order, $minutes ) {
global $wpdb;
$query_for_stock = \WC_Data_Store::load( 'product' )->get_query_for_stock( $product_id );
$query_for_reserved_stock = $this->get_query_for_reserved_stock( $product_id, $order->get_id() );
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$sql = $wpdb->prepare(
"
INSERT INTO {$wpdb->wc_reserved_stock} ( `order_id`, `product_id`, `stock_quantity`, `timestamp`, `expires` )
SELECT %d, %d, %d, NOW(), ( NOW() + INTERVAL %d MINUTE ) FROM DUAL
WHERE ( $query_for_stock FOR UPDATE ) - ( $query_for_reserved_stock FOR UPDATE ) >= %d
ON DUPLICATE KEY UPDATE `expires` = VALUES( `expires` ), `stock_quantity` = VALUES( `stock_quantity` )
",
$order->get_id(),
$product_id,
$stock_quantity,
$minutes,
$stock_quantity
);
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// Reliability: high concurrency on the same product reservation can trigger deadlocks (error codes 1213 and 1205).
// We currently do not have a reliable method to identify lock errors. The $wpdb interface does not consistently provide
// error codes, and error messages can vary by database locale. Previously, we matched messages to 'try restarting transaction'.
for ( $attempt = 0; $attempt < 3; ++$attempt ) {
$result = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( false !== $result ) {
break;
}
}
if ( ! $result ) {
$product = wc_get_product( $product_id );
throw new ReserveStockException(
'woocommerce_product_not_enough_stock',
sprintf(
/* translators: %s: product name */
__( 'Not enough units of %s are available in stock to fulfil this order.', 'woocommerce' ),
$product ? $product->get_name() : '#' . $product_id
),
403
);
}
}