Revise the stock + stock status saving logic (#11858)

* use set_stock to reset stock meta when not managing stock

Ensures that the 'woocommerce_{ variation | product }_set_stock' hooks fire to refllect the fact that stock becomes infinite.

* track state of Manage Stock? option

* quick/bulk edit fixes

* reapply quick and bulk edit fixes

* improve conditional reset logic that prevents actions from *_set_stock actions from firing with every save
This commit is contained in:
Manos Psychogyiopoulos 2016-10-12 14:51:40 +03:00 committed by Mike Jolley
parent a426004975
commit 4658245625
5 changed files with 98 additions and 79 deletions

View File

@ -257,9 +257,9 @@ class WC_Product {
* Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues). * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
* We cannot rely on the original loaded value in case another order was made since then. * We cannot rely on the original loaded value in case another order was made since then.
* *
* @param int $amount (default: null) * @param int $amount (default: null)
* @param string $mode can be set, add, or subtract * @param string $mode can be set, add, or subtract
* @return int new stock level * @return int new stock level
*/ */
public function set_stock( $amount = null, $mode = 'set' ) { public function set_stock( $amount = null, $mode = 'set' ) {
global $wpdb; global $wpdb;
@ -291,6 +291,14 @@ class WC_Product {
// Stock status // Stock status
$this->check_stock_status(); $this->check_stock_status();
// Trigger action
do_action( 'woocommerce_product_set_stock', $this );
// If not managing stock and clearing the stock meta, trigger action to indicate that stock has changed (infinite stock)
} elseif ( '' === $amount && '' !== get_post_meta( $this->id, '_stock', true ) ) {
update_post_meta( $this->id, '_stock', '' );
// Trigger action // Trigger action
do_action( 'woocommerce_product_set_stock', $this ); do_action( 'woocommerce_product_set_stock', $this );
} }

View File

@ -1148,11 +1148,20 @@ class WC_Admin_Post_Types {
} }
} }
// Handle stock status // Handle Stock Data
if ( isset( $_REQUEST['_stock_status'] ) ) { $manage_stock = ! empty( $_REQUEST['_manage_stock'] ) && 'grouped' !== $product->product_type ? 'yes' : 'no';
$stock_status = wc_clean( $_REQUEST['_stock_status'] ); $backorders = ! empty( $_REQUEST['_backorders'] ) ? wc_clean( $_REQUEST['_backorders'] ) : 'no';
$stock_status = ! empty( $_REQUEST['_stock_status'] ) ? wc_clean( $_REQUEST['_stock_status'] ) : 'instock';
$stock_amount = 'yes' === $manage_stock ? wc_stock_amount( $_REQUEST['_stock'] ) : '';
if ( $product->is_type( 'variable' ) ) { if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
// Apply product type constraints to stock status
if ( 'external' === $product->product_type ) {
// External always in stock
$stock_status = 'instock';
} elseif ( 'variable' === $product->product_type ) {
// Stock status is always determined by children
foreach ( $product->get_children() as $child_id ) { foreach ( $product->get_children() as $child_id ) {
if ( 'yes' !== get_post_meta( $child_id, '_manage_stock', true ) ) { if ( 'yes' !== get_post_meta( $child_id, '_manage_stock', true ) ) {
wc_update_product_stock_status( $child_id, $stock_status ); wc_update_product_stock_status( $child_id, $stock_status );
@ -1160,24 +1169,19 @@ class WC_Admin_Post_Types {
} }
WC_Product_Variable::sync_stock_status( $post_id ); WC_Product_Variable::sync_stock_status( $post_id );
} else { }
update_post_meta( $post_id, '_manage_stock', $manage_stock );
update_post_meta( $post_id, '_backorders', $backorders );
if ( 'variable' !== $product->product_type ) {
wc_update_product_stock_status( $post_id, $stock_status ); wc_update_product_stock_status( $post_id, $stock_status );
} }
}
// Handle stock wc_update_product_stock( $post_id, $stock_amount );
if ( ! $product->is_type( 'grouped' ) ) {
if ( isset( $_REQUEST['_manage_stock'] ) ) {
update_post_meta( $post_id, '_manage_stock', 'yes' );
wc_update_product_stock( $post_id, wc_stock_amount( $_REQUEST['_stock'] ) );
} else {
update_post_meta( $post_id, '_manage_stock', 'no' );
wc_update_product_stock( $post_id, 0 );
}
if ( ! empty( $_REQUEST['_backorders'] ) ) { } else {
update_post_meta( $post_id, '_backorders', wc_clean( $_REQUEST['_backorders'] ) ); wc_update_product_stock_status( $post_id, $stock_status );
}
} }
do_action( 'woocommerce_product_quick_edit_save', $product ); do_action( 'woocommerce_product_quick_edit_save', $product );
@ -1222,22 +1226,6 @@ class WC_Admin_Post_Types {
update_post_meta( $post_id, '_tax_class', $tax_class ); update_post_meta( $post_id, '_tax_class', $tax_class );
} }
if ( ! empty( $_REQUEST['_stock_status'] ) ) {
$stock_status = wc_clean( $_REQUEST['_stock_status'] );
if ( $product->is_type( 'variable' ) ) {
foreach ( $product->get_children() as $child_id ) {
if ( 'yes' !== get_post_meta( $child_id, '_manage_stock', true ) ) {
wc_update_product_stock_status( $child_id, $stock_status );
}
}
WC_Product_Variable::sync_stock_status( $post_id );
} else {
wc_update_product_stock_status( $post_id, $stock_status );
}
}
if ( ! empty( $_REQUEST['_shipping_class'] ) ) { if ( ! empty( $_REQUEST['_shipping_class'] ) ) {
$shipping_class = '_no_shipping_class' == $_REQUEST['_shipping_class'] ? '' : wc_clean( $_REQUEST['_shipping_class'] ); $shipping_class = '_no_shipping_class' == $_REQUEST['_shipping_class'] ? '' : wc_clean( $_REQUEST['_shipping_class'] );
@ -1380,27 +1368,50 @@ class WC_Admin_Post_Types {
} }
} }
// Handle stock // Handle Stock Data
if ( ! $product->is_type( 'grouped' ) ) { $was_managing_stock = get_post_meta( $post_id, '_manage_stock', true );
$stock_status = get_post_meta( $post_id, '_stock_status', true );
$backorders = get_post_meta( $post_id, '_stock_status', true );
if ( ! empty( $_REQUEST['change_stock'] ) ) { $backorders = ! empty( $_REQUEST['_backorders'] ) ? wc_clean( $_REQUEST['_backorders'] ) : $backorders;
update_post_meta( $post_id, '_manage_stock', 'yes' ); $stock_status = ! empty( $_REQUEST['_stock_status'] ) ? wc_clean( $_REQUEST['_stock_status'] ) : $stock_status;
wc_update_product_stock( $post_id, wc_stock_amount( $_REQUEST['_stock'] ) );
}
if ( ! empty( $_REQUEST['_manage_stock'] ) ) { if ( ! empty( $_REQUEST['_manage_stock'] ) ) {
$manage_stock = 'yes' === wc_clean( $_REQUEST['_manage_stock'] ) && 'grouped' !== $product->product_type ? 'yes' : 'no';
} else {
$manage_stock = $was_managing_stock;
}
if ( 'yes' === $_REQUEST['_manage_stock'] ) { $stock_amount = 'yes' === $manage_stock && isset( $_REQUEST['_change_stock'] ) ? wc_stock_amount( $_REQUEST['_change_stock'] ) : '';
update_post_meta( $post_id, '_manage_stock', 'yes' );
} else { if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
update_post_meta( $post_id, '_manage_stock', 'no' );
wc_update_product_stock( $post_id, 0 ); // Apply product type constraints to stock status
if ( 'external' === $product->product_type ) {
// External always in stock
$stock_status = 'instock';
} elseif ( 'variable' === $product->product_type ) {
// Stock status is always determined by children
foreach ( $product->get_children() as $child_id ) {
if ( 'yes' !== get_post_meta( $child_id, '_manage_stock', true ) ) {
wc_update_product_stock_status( $child_id, $stock_status );
}
} }
WC_Product_Variable::sync_stock_status( $post_id );
} }
if ( ! empty( $_REQUEST['_backorders'] ) ) { update_post_meta( $post_id, '_manage_stock', $manage_stock );
update_post_meta( $post_id, '_backorders', wc_clean( $_REQUEST['_backorders'] ) ); update_post_meta( $post_id, '_backorders', $backorders );
if ( 'variable' !== $product->product_type ) {
wc_update_product_stock_status( $post_id, $stock_status );
} }
wc_update_product_stock( $post_id, $stock_amount );
} else {
wc_update_product_stock_status( $post_id, $stock_status );
} }
do_action( 'woocommerce_product_bulk_edit_save', $product ); do_action( 'woocommerce_product_bulk_edit_save', $product );

View File

@ -1103,28 +1103,20 @@ class WC_Meta_Box_Product_Data {
} }
// Stock Data // Stock Data
$manage_stock = ! empty( $_POST['_manage_stock'] ) && 'grouped' !== $product_type ? 'yes' : 'no';
$backorders = ! empty( $_POST['_backorders'] ) && 'yes' === $manage_stock ? wc_clean( $_POST['_backorders'] ) : 'no';
$stock_status = ! empty( $_POST['_stock_status'] ) ? wc_clean( $_POST['_stock_status'] ) : 'instock';
$stock_amount = 'yes' === $manage_stock ? wc_stock_amount( $_POST['_stock'] ) : '';
if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
$manage_stock = 'no'; // Apply product type constraints to stock status
$backorders = 'no';
$stock_status = wc_clean( $_POST['_stock_status'] );
if ( 'external' === $product_type ) { if ( 'external' === $product_type ) {
// External always in stock
$stock_status = 'instock'; $stock_status = 'instock';
} elseif ( 'variable' === $product_type ) { } elseif ( 'variable' === $product_type ) {
// Stock status is always determined by children so sync later // Stock status is always determined by children so sync later
$stock_status = ''; $stock_status = '';
if ( ! empty( $_POST['_manage_stock'] ) ) {
$manage_stock = 'yes';
$backorders = wc_clean( $_POST['_backorders'] );
}
} elseif ( 'grouped' !== $product_type && ! empty( $_POST['_manage_stock'] ) ) {
$manage_stock = 'yes';
$backorders = wc_clean( $_POST['_backorders'] );
} }
update_post_meta( $post_id, '_manage_stock', $manage_stock ); update_post_meta( $post_id, '_manage_stock', $manage_stock );
@ -1134,13 +1126,10 @@ class WC_Meta_Box_Product_Data {
wc_update_product_stock_status( $post_id, $stock_status ); wc_update_product_stock_status( $post_id, $stock_status );
} }
if ( ! empty( $_POST['_manage_stock'] ) ) { wc_update_product_stock( $post_id, $stock_amount );
wc_update_product_stock( $post_id, wc_stock_amount( $_POST['_stock'] ) );
} else { } else {
update_post_meta( $post_id, '_stock', '' ); wc_update_product_stock_status( $post_id, $stock_status );
}
} elseif ( 'variable' !== $product_type ) {
wc_update_product_stock_status( $post_id, wc_clean( $_POST['_stock_status'] ) );
} }
// Cross sells and upsells // Cross sells and upsells
@ -1411,7 +1400,7 @@ class WC_Meta_Box_Product_Data {
wc_update_product_stock( $variation_id, wc_stock_amount( $variable_stock[ $i ] ) ); wc_update_product_stock( $variation_id, wc_stock_amount( $variable_stock[ $i ] ) );
} else { } else {
delete_post_meta( $variation_id, '_backorders' ); delete_post_meta( $variation_id, '_backorders' );
delete_post_meta( $variation_id, '_stock' ); wc_update_product_stock( $variation_id, '' );
} }
// Only update stock status to user setting if changed by the user, but do so before looking at stock levels at variation level // Only update stock status to user setting if changed by the user, but do so before looking at stock levels at variation level

View File

@ -1208,8 +1208,8 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
// Don't manage stock. // Don't manage stock.
update_post_meta( $product->id, '_manage_stock', 'no' ); update_post_meta( $product->id, '_manage_stock', 'no' );
update_post_meta( $product->id, '_backorders', $backorders ); update_post_meta( $product->id, '_backorders', $backorders );
update_post_meta( $product->id, '_stock', '' );
wc_update_product_stock( $product->id, '' );
wc_update_product_stock_status( $product->id, $stock_status ); wc_update_product_stock_status( $product->id, $stock_status );
} }
} elseif ( 'variable' !== $product_type ) { } elseif ( 'variable' !== $product_type ) {
@ -1482,7 +1482,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
} }
} else { } else {
delete_post_meta( $variation_id, '_backorders' ); delete_post_meta( $variation_id, '_backorders' );
delete_post_meta( $variation_id, '_stock' ); wc_update_product_stock( $variation_id, '' );
} }
// Regular Price. // Regular Price.

View File

@ -437,9 +437,9 @@ class WC_Product_Variation extends WC_Product {
* Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues). * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
* We cannot rely on the original loaded value in case another order was made since then. * We cannot rely on the original loaded value in case another order was made since then.
* *
* @param int $amount * @param int $amount
* @param string $mode can be set, add, or subtract * @param string $mode can be set, add, or subtract
* @return int new stock level * @return int new stock level
*/ */
public function set_stock( $amount = null, $mode = 'set' ) { public function set_stock( $amount = null, $mode = 'set' ) {
global $wpdb; global $wpdb;
@ -477,6 +477,17 @@ class WC_Product_Variation extends WC_Product {
// Trigger action // Trigger action
do_action( 'woocommerce_variation_set_stock', $this ); do_action( 'woocommerce_variation_set_stock', $this );
// If not managing stock and clearing the stock meta, trigger action to indicate that stock has changed (infinite stock)
} elseif ( '' === $amount ) {
if ( false !== get_post_meta( $this->variation_id, '_stock' ) ) {
delete_post_meta( $this->variation_id, '_stock' );
// Trigger action
do_action( 'woocommerce_variation_set_stock', $this );
}
// If not managing stock and setting stock, apply changes to the parent
} elseif ( ! is_null( $amount ) ) { } elseif ( ! is_null( $amount ) ) {
return $this->parent->set_stock( $amount, $mode ); return $this->parent->set_stock( $amount, $mode );
} }