Different Hold stock minutes per Payment Method
-
is it possibile to setup different “hold stock minutes” for different payment methods?
is there some hook for that?
-
Hi @bluantinoo
Try using the below code snippet in the active theme functions.php file.
add_action( 'woocommerce_checkout_order_created', 'wc_reserve_stock_for_specific_payment_gateway', 5 );
function wc_reserve_stock_for_specific_payment_gateway( $order ) {
// Define the specific payment ID(s)
$target_payment_ids = array('cod', 'bacs');
// Define the time in minutes to hold stock
$stock_hold_minutes = 150;
if ( in_array( $order->get_payment_method(), $target_payment_ids ) ) {
// Remove the default functionality to hold stock for 60 minutes
remove_action( 'woocommerce_checkout_order_created', 'wc_reserve_stock_for_order' );
if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) {
return;
}
$order = $order instanceof WC_Order ? $order : wc_get_order( $order );
if ( is_object( $order ) ) {
// Restore the functionality with a custom delay to hold the stock
( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->reserve_stock_for_order( $order, $stock_hold_minutes );
}
}
}Actually even if the reserve stock expires is set accordingly to the filter,
The order gets cancelled anyway after the “Hold stock (minutes)” set in Woocomerce Inventory Settings.
I tried to set WC Hold stock to 5 minutes, and put $stock_hold_minutes = 2880 in filter for an asyncronous payment method that may need up to 48 hours.
In the wp_wc_reserved_stock the expires time is correct.
But order gets cancelled after 5 minutes.
I think we should look to ‘woocommerce_cancel_unpaid_order’ hook as wellmaybe we’re missing something?
- This reply was modified 2 months, 1 week ago by bluantinoo.
Which Checkout are you using for testing this?
For Store API/Checkout block, stock reserve happens before we reach the payment method, so you can hook into
woocommerce_store_api_checkout_update_order_from_request
and change the value ofwoocommerce_order_hold_stock_minutes
Code example (need a different top hook for old Checkout):
add_action('woocommerce_store_api_checkout_update_order_from_request', function($order, $request) {
add_filter( 'woocommerce_order_hold_stock_minutes', function( $minutes, $order ) use ($request) {
$payment_method = $request->get_param('payment_method');
if ($payment_method === 'cod') {
return 37;
}
return $minutes;
}, 10, 2 );
}, 10, 2);@assassinateur not sure 100% what you’re asking, but I’m speaking about standard checkout, the one usually at shop.com/checkout url.
Anyway, I managed to solve the issue adding to the @mujuonly solution another hook towoocommerce_cancel_unpaid_order
taking care of checking if the woocommerce_cancel_unpaid_orders cron is allowed to delete the order or not.Just to be clear for anyone could use this, I post the entire code:
Just
/* this set a longer hold stock in minutes for specific payment methods orders */
add_action( 'woocommerce_checkout_order_created', 'ixxx_reserve_stock_for_specific_payment_gateway', 5 );
function xxx_reserve_stock_for_specific_payment_gateway( $order ) {
// Define the specific payment ID(s)
$target_payment_ids = array('komoju_konbini', 'omise_konbini');
// Define the time in minutes to hold stock
$stock_hold_minutes = 10;
if ( in_array( $order->get_payment_method(), $target_payment_ids ) ) {
// Remove the default functionality to hold stock for 60 minutes
remove_action( 'woocommerce_checkout_order_created', 'wc_reserve_stock_for_order' );
if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) {
return;
}
$order = $order instanceof WC_Order ? $order : wc_get_order( $order );
if ( is_object( $order ) ) {
// Restore the functionality with a custom delay to hold the stock
( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->reserve_stock_for_order( $order, $stock_hold_minutes );
}
}
}
/* This avoid that the cron job change order status to cancelled untill it's time */
add_filter( 'woocommerce_cancel_unpaid_order', 'xxx_check_if_order_has_to_be_canceled', 10, 2 );
function xxx_check_if_order_has_to_be_canceled( $created_via, $order ){
if ( 'checkout' != $created_via ){
return false;
}
// Define the specific payment ID(s)
$target_payment_ids = array('komoju_konbini', 'omise_konbini');
// define intervall
$stock_hold_minutes = 2880; // 48 hours
if ( in_array( $order->get_payment_method(), $target_payment_ids ) ) {
$order_date_created = $order->get_date_created();
$current_date = current_datetime();
$deadline_date = $order_date_created->modify( '+' . $stock_hold_minutes . ' minutes' )->format('Y-m-d H:i:s');
if ( $current_date->format('Y-m-d H:i:s') < $deadline_date ){
return false;
} else {
return true;
}
} else {
// for all other payment methods
return true;
}
}Anyone welcome in improving it.
Glad you got that to work, just noting that the above logic will only work for orders created via the shortcode Checkout.
Starting November last year, the new default Checkout has changed to Checkout block.
thanks for your advice @assassinateur
I’m actually using Elementor pro so I guess it is using the shortcode version.
which other checkout types exist?
Hi @bluantinoo
WooCommerce primarily has two types of checkout: The Checkout Block and Shortcode. More info can be found here:
- https://woocommerce.com/document/woocommerce-store-editing/customizing-cart-and-checkout/checkout-block/
- https://woocommerce.com/document/woocommerce-shortcodes/page-shortcodes/#checkout
I hope this clarifies your concern. If you have any other questions, feel free to ask.
- You must be logged in to reply to this topic.