From d021980c10bdac699437254090ba1159a9ddfc6e Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Tue, 13 Aug 2013 16:56:09 +0100 Subject: [PATCH] Rather than have hooks *everywhere* use a single set stock function in admin and on the frontend Closes #3593 --- includes/abstracts/abstract-wc-product.php | 57 +++------ .../post-types/class-wc-admin-cpt-product.php | 17 +-- .../class-wc-meta-box-product-data.php | 41 +++---- includes/class-wc-product-variable.php | 74 +----------- includes/class-wc-product-variation.php | 112 +++++++----------- includes/wc-product-functions.php | 27 ++++- 6 files changed, 120 insertions(+), 208 deletions(-) diff --git a/includes/abstracts/abstract-wc-product.php b/includes/abstracts/abstract-wc-product.php index 1eb609ac965..f44dfabefd9 100644 --- a/includes/abstracts/abstract-wc-product.php +++ b/includes/abstracts/abstract-wc-product.php @@ -151,26 +151,33 @@ class WC_Product { /** * Set stock level of the product. * - * @access public * @param mixed $amount (default: null) * @return int Stock */ public function set_stock( $amount = null ) { - global $woocommerce; + if ( is_null( $amount ) ) + return; - if ( $this->managing_stock() && ! is_null( $amount ) ) { + if ( $this->managing_stock() ) { + + // Update stock amount $this->stock = intval( $amount ); + + // Update meta update_post_meta( $this->id, '_stock', $this->stock ); - do_action( 'woocommerce_product_set_stock', $this ); - - // Out of stock attribute + // Update stock status if ( ! $this->backorders_allowed() && $this->get_total_stock() <= 0 ) $this->set_stock_status( 'outofstock' ); + elseif ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) $this->set_stock_status( 'instock' ); - wc_delete_product_transients( $this->id ); // Clear transient + // Clear total stock transient + delete_transient( 'wc_product_total_stock_' . $this->id ); + + // Trigger action + do_action( 'woocommerce_product_set_stock', $this ); return $this->get_stock_quantity(); } @@ -179,53 +186,21 @@ class WC_Product { /** * Reduce stock level of the product. * - * @access public * @param int $by (default: 1) Amount to reduce by. * @return int Stock */ public function reduce_stock( $by = 1 ) { - global $woocommerce; - - if ( $this->managing_stock() ) { - $this->stock = $this->stock - $by; - update_post_meta( $this->id, '_stock', $this->stock ); - - do_action( 'woocommerce_product_reduce_stock', $this, $by ); - - // Out of stock attribute - if ( ! $this->backorders_allowed() && $this->get_total_stock() <= 0 ) - $this->set_stock_status( 'outofstock' ); - - wc_delete_product_transients( $this->id ); // Clear transient - - return $this->get_stock_quantity(); - } + return $this->set_stock( $this->stock - $by ); } /** * Increase stock level of the product. * - * @access public * @param int $by (default: 1) Amount to increase by * @return int Stock */ public function increase_stock( $by = 1 ) { - global $woocommerce; - - if ( $this->managing_stock() ) { - $this->stock = $this->stock + $by; - update_post_meta( $this->id, '_stock', $this->stock ); - - do_action( 'woocommerce_product_increase_stock', $this, $by ); - - // Out of stock attribute - if ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) - $this->set_stock_status( 'instock' ); - - wc_delete_product_transients( $this->id ); // Clear transient - - return $this->get_stock_quantity(); - } + return $this->set_stock( $this->stock + $by ); } /** diff --git a/includes/admin/post-types/class-wc-admin-cpt-product.php b/includes/admin/post-types/class-wc-admin-cpt-product.php index 4850f251880..16b72abb69b 100644 --- a/includes/admin/post-types/class-wc-admin-cpt-product.php +++ b/includes/admin/post-types/class-wc-admin-cpt-product.php @@ -151,7 +151,7 @@ class WC_Admin_CPT_Product extends WC_Admin_CPT { if ( isset( $_POST['_visibility'] ) ) update_post_meta( $post_id, '_visibility', stripslashes( $_POST['_visibility'] ) ); if ( isset( $_POST['_stock_status'] ) ) - update_post_meta( $post_id, '_stock_status', stripslashes( $_POST['_stock_status'] ) ); + wc_update_product_stock_status( $post_id, woocommerce_clean( $_POST['_stock_status'] ) ); } /** @@ -683,7 +683,6 @@ class WC_Admin_CPT_Product extends WC_Admin_CPT { if ( isset( $_REQUEST['_length'] ) ) update_post_meta( $post_id, '_length', woocommerce_clean( $_REQUEST['_length'] ) ); if ( isset( $_REQUEST['_width'] ) ) update_post_meta( $post_id, '_width', woocommerce_clean( $_REQUEST['_width'] ) ); if ( isset( $_REQUEST['_height'] ) ) update_post_meta( $post_id, '_height', woocommerce_clean( $_REQUEST['_height'] ) ); - if ( isset( $_REQUEST['_stock_status'] ) ) update_post_meta( $post_id, '_stock_status', woocommerce_clean( $_REQUEST['_stock_status'] ) ); if ( isset( $_REQUEST['_visibility'] ) ) update_post_meta( $post_id, '_visibility', woocommerce_clean( $_REQUEST['_visibility'] ) ); if ( isset( $_REQUEST['_featured'] ) ) update_post_meta( $post_id, '_featured', 'yes' ); else update_post_meta( $post_id, '_featured', 'no' ); @@ -716,14 +715,18 @@ class WC_Admin_CPT_Product extends WC_Admin_CPT { } } + // Handle stock status + if ( isset( $_REQUEST['_stock_status'] ) ) + wc_update_product_stock_status( $post_id, woocommerce_clean( $_REQUEST['_stock_status'] ) ); + // Handle stock if ( ! $product->is_type('grouped') ) { if ( isset( $_REQUEST['_manage_stock'] ) ) { update_post_meta( $post_id, '_manage_stock', 'yes' ); - update_post_meta( $post_id, '_stock', (int) $_REQUEST['_stock'] ); + wc_update_product_stock( $post_id, intval( $_REQUEST['_stock'] ) ); } else { update_post_meta( $post_id, '_manage_stock', 'no' ); - update_post_meta( $post_id, '_stock', '0' ); + wc_update_product_stock( $post_id, 0 ); } } @@ -762,7 +765,7 @@ class WC_Admin_CPT_Product extends WC_Admin_CPT { } if ( ! empty( $_REQUEST['_stock_status'] ) ) - update_post_meta( $post_id, '_stock_status', stripslashes( $_REQUEST['_stock_status'] ) ); + wc_update_product_stock_status( $post_id, woocommerce_clean( $_REQUEST['_stock_status'] ) ); if ( ! empty( $_REQUEST['_visibility'] ) ) update_post_meta( $post_id, '_visibility', stripslashes( $_REQUEST['_visibility'] ) ); @@ -872,8 +875,8 @@ class WC_Admin_CPT_Product extends WC_Admin_CPT { if ( ! $product->is_type( 'grouped' ) ) { if ( ! empty( $_REQUEST['change_stock'] ) ) { - update_post_meta( $post_id, '_stock', (int) $_REQUEST['_stock'] ); update_post_meta( $post_id, '_manage_stock', 'yes' ); + wc_update_product_stock( $post_id, intval( $_REQUEST['_stock'] ) ); } if ( ! empty( $_REQUEST['_manage_stock'] ) ) { @@ -882,7 +885,7 @@ class WC_Admin_CPT_Product extends WC_Admin_CPT { update_post_meta( $post_id, '_manage_stock', 'yes' ); } else { update_post_meta( $post_id, '_manage_stock', 'no' ); - update_post_meta( $post_id, '_stock', '0' ); + wc_update_product_stock( $post_id, 0 ); } } diff --git a/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php b/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php index 518d744e473..58c51777da6 100644 --- a/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php +++ b/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php @@ -1148,44 +1148,40 @@ class WC_Meta_Box_Product_Data { if ( $product_type == 'grouped' ) { - update_post_meta( $post_id, '_stock_status', stripslashes( $_POST['_stock_status'] ) ); - update_post_meta( $post_id, '_stock', '' ); update_post_meta( $post_id, '_manage_stock', 'no' ); update_post_meta( $post_id, '_backorders', 'no' ); + update_post_meta( $post_id, '_stock', '' ); + + wc_update_product_stock_status( $post_id, woocommerce_clean( $_POST['_stock_status'] ) ); } elseif ( $product_type == 'external' ) { - update_post_meta( $post_id, '_stock_status', 'instock' ); - update_post_meta( $post_id, '_stock', '' ); update_post_meta( $post_id, '_manage_stock', 'no' ); update_post_meta( $post_id, '_backorders', 'no' ); + update_post_meta( $post_id, '_stock', '' ); + + wc_update_product_stock_status( $post_id, 'instock' ); } elseif ( ! empty( $_POST['_manage_stock'] ) ) { - // Manage stock - update_post_meta( $post_id, '_stock', (int) $_POST['_stock'] ); - update_post_meta( $post_id, '_stock_status', stripslashes( $_POST['_stock_status'] ) ); - update_post_meta( $post_id, '_backorders', stripslashes( $_POST['_backorders'] ) ); update_post_meta( $post_id, '_manage_stock', 'yes' ); + update_post_meta( $post_id, '_backorders', woocommerce_clean( $_POST['_backorders'] ) ); - // Check stock level - if ( $product_type !== 'variable' && $_POST['_backorders'] == 'no' && (int) $_POST['_stock'] < 1 ) - update_post_meta( $post_id, '_stock_status', 'outofstock' ); + wc_update_product_stock_status( $post_id, woocommerce_clean( $_POST['_stock_status'] ) ); + wc_update_product_stock( $post_id, intval( $_POST['_stock'] ) ); } else { // Don't manage stock - update_post_meta( $post_id, '_stock', '' ); - update_post_meta( $post_id, '_stock_status', stripslashes( $_POST['_stock_status'] ) ); - update_post_meta( $post_id, '_backorders', stripslashes( $_POST['_backorders'] ) ); update_post_meta( $post_id, '_manage_stock', 'no' ); + update_post_meta( $post_id, '_backorders', woocommerce_clean( $_POST['_backorders'] ) ); + update_post_meta( $post_id, '_stock', '' ); + wc_update_product_stock_status( $post_id, woocommerce_clean( $_POST['_stock_status'] ) ); } } else { - - update_post_meta( $post_id, '_stock_status', stripslashes( $_POST['_stock_status'] ) ); - + wc_update_product_stock_status( $post_id, woocommerce_clean( $_POST['_stock_status'] ) ); } // Upsells @@ -1274,6 +1270,8 @@ class WC_Meta_Box_Product_Data { public static function save_variations( $post_id, $post ) { global $woocommerce, $wpdb; + $attributes = (array) maybe_unserialize( get_post_meta( $post_id, '_product_attributes', true ) ); + if ( isset( $_POST['variable_sku'] ) ) { $variable_post_id = $_POST['variable_post_id']; @@ -1299,8 +1297,6 @@ class WC_Meta_Box_Product_Data { $variable_is_virtual = isset( $_POST['variable_is_virtual'] ) ? $_POST['variable_is_virtual'] : array(); $variable_is_downloadable = isset( $_POST['variable_is_downloadable'] ) ? $_POST['variable_is_downloadable'] : array(); - $attributes = (array) maybe_unserialize( get_post_meta( $post_id, '_product_attributes', true ) ); - $max_loop = max( array_keys( $_POST['variable_post_id'] ) ); for ( $i = 0; $i <= $max_loop; $i ++ ) { @@ -1348,17 +1344,16 @@ class WC_Meta_Box_Product_Data { // Update post meta update_post_meta( $variation_id, '_sku', woocommerce_clean( $variable_sku[ $i ] ) ); update_post_meta( $variation_id, '_weight', woocommerce_clean( $variable_weight[ $i ] ) ); - update_post_meta( $variation_id, '_length', woocommerce_clean( $variable_length[ $i ] ) ); update_post_meta( $variation_id, '_width', woocommerce_clean( $variable_width[ $i ] ) ); update_post_meta( $variation_id, '_height', woocommerce_clean( $variable_height[ $i ] ) ); - - update_post_meta( $variation_id, '_stock', woocommerce_clean( $variable_stock[ $i ] ) ); update_post_meta( $variation_id, '_thumbnail_id', absint( $upload_image_id[ $i ] ) ); - update_post_meta( $variation_id, '_virtual', woocommerce_clean( $is_virtual ) ); update_post_meta( $variation_id, '_downloadable', woocommerce_clean( $is_downloadable ) ); + // Stock handling + wc_update_product_stock( $variation_id, woocommerce_clean( $variable_stock[ $i ] ) ); + // Price handling $regular_price = woocommerce_clean( $variable_regular_price[ $i ] ); $sale_price = woocommerce_clean( $variable_sale_price[ $i ] ); diff --git a/includes/class-wc-product-variable.php b/includes/class-wc-product-variable.php index 088b3913393..1df98224963 100644 --- a/includes/class-wc-product-variable.php +++ b/includes/class-wc-product-variable.php @@ -68,83 +68,17 @@ class WC_Product_Variable extends WC_Product { /** * Set stock level of the product. * - * @access public * @param mixed $amount (default: null) * @return int Stock */ function set_stock( $amount = null ) { - global $woocommerce; + // Empty total stock so its refreshed + $this->total_stock = ''; - if ( $this->managing_stock() && ! is_null( $amount ) ) { - - $this->stock = intval( $amount ); - $this->total_stock = intval( $amount ); - update_post_meta( $this->id, '_stock', $this->stock ); - - // Check parents out of stock attribute - if ( ! $this->backorders_allowed() && $this->get_total_stock() <= 0 ) - $this->set_stock_status( 'outofstock' ); - elseif ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) - $this->set_stock_status( 'instock' ); - - wc_delete_product_transients( $this->id ); // Clear transient - - return apply_filters( 'woocommerce_stock_amount', $this->stock ); - } + // Call parent set_stock + return parent::set_stock( $amount ); } - /** - * Reduce stock level of the product. - * - * @access public - * @param int $by (default: 1) Amount to reduce by. - * @return int Stock - */ - public function reduce_stock( $by = 1 ) { - global $woocommerce; - - if ( $this->managing_stock() ) { - $this->stock = $this->stock - $by; - $this->total_stock = $this->get_total_stock() - $by; - update_post_meta($this->id, '_stock', $this->stock); - - // Out of stock attribute - if ( ! $this->backorders_allowed() && $this->get_total_stock() <= 0 ) - $this->set_stock_status( 'outofstock' ); - - wc_delete_product_transients( $this->id ); // Clear transient - - return apply_filters( 'woocommerce_stock_amount', $this->stock ); - } - } - - - /** - * Increase stock level of the product. - * - * @access public - * @param int $by (default: 1) Amount to increase by - * @return int Stock - */ - public function increase_stock( $by = 1 ) { - global $woocommerce; - - if ($this->managing_stock()) : - $this->stock = $this->stock + $by; - $this->total_stock = $this->get_total_stock() + $by; - update_post_meta($this->id, '_stock', $this->stock); - - // Out of stock attribute - if ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) - $this->set_stock_status( 'instock' ); - - wc_delete_product_transients( $this->id ); // Clear transient - - return apply_filters( 'woocommerce_stock_amount', $this->stock ); - endif; - } - - /** * Return the products children posts. * diff --git a/includes/class-wc-product-variation.php b/includes/class-wc-product-variation.php index de2d6ef979a..80364fbfec4 100644 --- a/includes/class-wc-product-variation.php +++ b/includes/class-wc-product-variation.php @@ -281,76 +281,71 @@ class WC_Product_Variation extends WC_Product { } /** - * Set stock level of the product. + * Set stock level of the product variation. * - * @access public - * @param mixed $amount (default: null) - * @return int Stock + * @param int $amount + * @param boolean $force_variation_stock If true, the variation's stock will be updated and not the parents. */ - function set_stock( $amount = null ) { - global $woocommerce; + function set_stock( $amount = null, $force_variation_stock = false ) { + if ( is_null( $amount ) ) + return; - if ( $this->variation_has_stock ) { - if ( $this->managing_stock() && ! is_null( $amount ) ) { + if ( $amount === '' && $force_variation_stock ) { - $this->stock = intval( $amount ); - $this->total_stock = intval( $amount ); - update_post_meta( $this->variation_id, '_stock', $this->stock ); - wc_delete_product_transients( $this->id ); // Clear transient + // If amount is an empty string, stock management is being turned off at variation level + $this->variation_has_stock = false; + $this->stock = ''; + unset( $this->manage_stock ); - // Check parents out of stock attribute - if ( ! $this->is_in_stock() ) { + // Update meta + update_post_meta( $this->variation_id, '_stock', '' ); - // Check parent - $parent_product = get_product( $this->id ); + } elseif ( $this->variation_has_stock || $force_variation_stock ) { - // Only continue if the parent has backorders off - if ( ! $parent_product->backorders_allowed() && $parent_product->get_total_stock() <= 0 ) - $this->set_stock_status( 'outofstock' ); + // Update stock amount + $this->stock = intval( $amount ); - } elseif ( $this->is_in_stock() ) { - $this->set_stock_status( 'instock' ); - } + // Update meta + update_post_meta( $this->variation_id, '_stock', $this->stock ); - return apply_filters( 'woocommerce_stock_amount', $this->stock ); + // Clear total stock transient + delete_transient( 'wc_product_total_stock_' . $this->id ); + + // Check parents out of stock attribute + if ( ! $this->is_in_stock() ) { + + // Check parent + $parent_product = get_product( $this->id ); + + // Only continue if the parent has backorders off + if ( ! $parent_product->backorders_allowed() && $parent_product->get_total_stock() <= 0 ) + $this->set_stock_status( 'outofstock' ); + + } elseif ( $this->is_in_stock() ) { + $this->set_stock_status( 'instock' ); } + + // Trigger action + do_action( 'woocommerce_product_set_stock', $this ); + + return $this->get_stock_quantity(); + } else { + return parent::set_stock( $amount ); + } } /** * Reduce stock level of the product. * - * @access public * @param int $by (default: 1) Amount to reduce by * @return int stock level */ public function reduce_stock( $by = 1 ) { - global $woocommerce; - if ( $this->variation_has_stock ) { - if ( $this->managing_stock() ) { - - $this->stock = $this->stock - $by; - $this->total_stock = $this->total_stock - $by; - update_post_meta( $this->variation_id, '_stock', $this->stock ); - wc_delete_product_transients( $this->id ); // Clear transient - - // Check parents out of stock attribute - if ( ! $this->is_in_stock() ) { - - // Check parent - $parent_product = get_product( $this->id ); - - // Only continue if the parent has backorders off - if ( ! $parent_product->backorders_allowed() && $parent_product->get_total_stock() <= 0 ) - $this->set_stock_status( 'outofstock' ); - - } - - return apply_filters( 'woocommerce_stock_amount', $this->stock ); - } + return $this->set_stock( $this->stock - $by ); } else { return parent::reduce_stock( $by ); } @@ -359,30 +354,15 @@ class WC_Product_Variation extends WC_Product { /** * Increase stock level of the product. * - * @access public * @param int $by (default: 1) Amount to increase by * @return int stock level */ public function increase_stock( $by = 1 ) { - global $woocommerce; - - if ($this->variation_has_stock) : - if ($this->managing_stock()) : - - $this->stock = $this->stock + $by; - $this->total_stock = $this->total_stock + $by; - update_post_meta( $this->variation_id, '_stock', $this->stock ); - wc_delete_product_transients( $this->id ); // Clear transient - - // Parents out of stock attribute - if ( $this->is_in_stock() ) - $this->set_stock_status( 'instock' ); - - return apply_filters( 'woocommerce_stock_amount', $this->stock ); - endif; - else : + if ( $this->variation_has_stock ) { + return $this->set_stock( $this->stock + $by ); + } else { return parent::increase_stock( $by ); - endif; + } } /** diff --git a/includes/wc-product-functions.php b/includes/wc-product-functions.php index 53a824c7852..cb8d658f26e 100644 --- a/includes/wc-product-functions.php +++ b/includes/wc-product-functions.php @@ -13,7 +13,6 @@ /** * Main function for returning products, uses the WC_Product_Factory class. * - * @access public * @param mixed $the_product Post object or post ID of the product. * @param array $args (default: array()) Contains all arguments to be used to get this product. * @return WC_Product @@ -23,6 +22,32 @@ function get_product( $the_product = false, $args = array() ) { return $woocommerce->product_factory->get_product( $the_product, $args ); } +/** + * Update a product's stock amount + * + * @param int $product_id + * @param int $new_stock_level + */ +function wc_update_product_stock( $product_id, $new_stock_level ) { + $product = get_product( $product_id ); + + if ( $product->is_type( 'variation' ) ) + $product->set_stock( $new_stock_level, true ); + else + $product->set_stock( $new_stock_level ); +} + +/** + * Update a product's stock status + * + * @param int $product_id + * @param int $status + */ +function wc_update_product_stock_status( $product_id, $status ) { + $product = get_product( $product_id ); + $product-> set_stock_status( $status ); +} + /** * Clear all transients cache for product data. *