Fix stock status setting for variable products on bulk & quick edits.

For bulk edit: even if stock status was left as "No change", the
status of all variations was being changed to whatever the status
of the product was before it was converted to variable. Now
no change is performed when "No change" is selected, and all
variations change to whatever is selected otherwise.

For quick edit: a new "No change" option is added that will be
preselected when the product is variable. Previously, whatever
status the product had before being converted to variable was being
shown, and that's the status that would be set when saving.
Also, a "This will change the stock status of all variations"
message is displayed before the selector.
This commit is contained in:
Nestor Soriano 2020-04-14 12:48:02 +02:00
parent 39e5a1bfb1
commit fd34cf76b2
3 changed files with 38 additions and 23 deletions

View File

@ -31,7 +31,8 @@ jQuery(
menu_order = $wc_inline_data.find( '.menu_order' ).text(), menu_order = $wc_inline_data.find( '.menu_order' ).text(),
tax_status = $wc_inline_data.find( '.tax_status' ).text(), tax_status = $wc_inline_data.find( '.tax_status' ).text(),
tax_class = $wc_inline_data.find( '.tax_class' ).text(), tax_class = $wc_inline_data.find( '.tax_class' ).text(),
backorders = $wc_inline_data.find( '.backorders' ).text(); backorders = $wc_inline_data.find( '.backorders' ).text(),
product_type = $wc_inline_data.find( '.product_type' ).text();
var formatted_regular_price = regular_price.replace( '.', woocommerce_admin.mon_decimal_point ), var formatted_regular_price = regular_price.replace( '.', woocommerce_admin.mon_decimal_point ),
formatted_sale_price = sale_price.replace( '.', woocommerce_admin.mon_decimal_point ); formatted_sale_price = sale_price.replace( '.', woocommerce_admin.mon_decimal_point );
@ -58,10 +59,14 @@ jQuery(
'select[name="_backorders"] option' 'select[name="_backorders"] option'
).removeAttr( 'selected' ); ).removeAttr( 'selected' );
var is_variable_product = 'variable' === product_type;
$( 'select[name="_stock_status"] ~ .quick-edit-warning', '.inline-edit-row' ).toggle( is_variable_product );
$( 'select[name="_stock_status"] option[value="' + (is_variable_product ? '' : stock_status) + '"]', '.inline-edit-row' )
.attr( 'selected', 'selected' );
$( 'select[name="_tax_status"] option[value="' + tax_status + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' ); $( 'select[name="_tax_status"] option[value="' + tax_status + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' );
$( 'select[name="_tax_class"] option[value="' + tax_class + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' ); $( 'select[name="_tax_class"] option[value="' + tax_class + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' );
$( 'select[name="_visibility"] option[value="' + visibility + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' ); $( 'select[name="_visibility"] option[value="' + visibility + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' );
$( 'select[name="_stock_status"] option[value="' + stock_status + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' );
$( 'select[name="_backorders"] option[value="' + backorders + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' ); $( 'select[name="_backorders"] option[value="' + backorders + '"]', '.inline-edit-row' ).attr( 'selected', 'selected' );
if ( 'yes' === featured ) { if ( 'yes' === featured ) {
@ -71,8 +76,7 @@ jQuery(
} }
// Conditional display. // Conditional display.
var product_type = $wc_inline_data.find( '.product_type' ).text(), var product_is_virtual = $wc_inline_data.find( '.product_is_virtual' ).text();
product_is_virtual = $wc_inline_data.find( '.product_is_virtual' ).text();
var product_supports_stock_status = 'external' !== product_type; var product_supports_stock_status = 'external' !== product_type;
var product_supports_stock_fields = 'external' !== product_type && 'grouped' !== product_type; var product_supports_stock_fields = 'external' !== product_type && 'grouped' !== product_type;

View File

@ -417,9 +417,14 @@ class WC_Admin_Post_Types {
// Handle Stock Data. // Handle Stock Data.
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$manage_stock = ! empty( $_REQUEST['_manage_stock'] ) && 'grouped' !== $product->get_type() ? 'yes' : 'no'; $manage_stock = ! empty( $_REQUEST['_manage_stock'] ) && 'grouped' !== $product->get_type() ? 'yes' : 'no';
$backorders = ! empty( $_REQUEST['_backorders'] ) ? wc_clean( $_REQUEST['_backorders'] ) : 'no'; $backorders = ! empty( $_REQUEST['_backorders'] ) ? wc_clean( $_REQUEST['_backorders'] ) : 'no';
$stock_status = ! empty( $_REQUEST['_stock_status'] ) ? wc_clean( $_REQUEST['_stock_status'] ) : 'instock'; $stock_status_in_request = ! empty( $_REQUEST['_stock_status'] );
if ( $stock_status_in_request ) {
$stock_status = wc_clean( $_REQUEST['_stock_status'] );
} else {
$stock_status = $product->is_type( 'variable' ) ? null : 'instock';
}
$stock_amount = 'yes' === $manage_stock && isset( $_REQUEST['_stock'] ) && is_numeric( wp_unslash( $_REQUEST['_stock'] ) ) ? wc_stock_amount( wp_unslash( $_REQUEST['_stock'] ) ) : ''; $stock_amount = 'yes' === $manage_stock && isset( $_REQUEST['_stock'] ) && is_numeric( wp_unslash( $_REQUEST['_stock'] ) ) ? wc_stock_amount( wp_unslash( $_REQUEST['_stock'] ) ) : '';
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized // phpcs:enable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
@ -531,10 +536,8 @@ class WC_Admin_Post_Types {
// Handle Stock Data. // Handle Stock Data.
$was_managing_stock = $product->get_manage_stock() ? 'yes' : 'no'; $was_managing_stock = $product->get_manage_stock() ? 'yes' : 'no';
$stock_status = $product->get_stock_status();
$backorders = $product->get_backorders(); $backorders = $product->get_backorders();
$backorders = ! empty( $_REQUEST['_backorders'] ) ? wc_clean( $_REQUEST['_backorders'] ) : $backorders; $backorders = ! empty( $_REQUEST['_backorders'] ) ? wc_clean( $_REQUEST['_backorders'] ) : $backorders;
$stock_status = ! empty( $_REQUEST['_stock_status'] ) ? wc_clean( $_REQUEST['_stock_status'] ) : $stock_status;
if ( ! empty( $_REQUEST['_manage_stock'] ) ) { if ( ! empty( $_REQUEST['_manage_stock'] ) ) {
$manage_stock = 'yes' === wc_clean( $_REQUEST['_manage_stock'] ) && 'grouped' !== $product->get_type() ? 'yes' : 'no'; $manage_stock = 'yes' === wc_clean( $_REQUEST['_manage_stock'] ) && 'grouped' !== $product->get_type() ? 'yes' : 'no';
@ -566,7 +569,8 @@ class WC_Admin_Post_Types {
$product->set_manage_stock( 'no' ); $product->set_manage_stock( 'no' );
} }
$product = $this->update_stock_status( $product, $stock_status ); $stock_status = empty( $_REQUEST['_stock_status'] ) ? null : wc_clean( $_REQUEST['_stock_status'] );
$product = $this->update_stock_status( $product, $stock_status );
$product->save(); $product->save();
@ -872,26 +876,28 @@ class WC_Admin_Post_Types {
/** /**
* Apply product type constraints to stock status. * Apply product type constraints to stock status.
* *
* @param WC_Product $product The product whose stock status will be adjusted. * @param WC_Product $product The product whose stock status will be adjusted.
* @param string $stock_status The stock status to use for adjustment. * @param string|null $stock_status The stock status to use for adjustment, or null if no new stock status has been supplied in the request.
* @return WC_Product The supplied product, or the synced product if it was a variable product. * @return WC_Product The supplied product, or the synced product if it was a variable product.
*/ */
private function update_stock_status( $product, $stock_status ) { private function update_stock_status( $product, $stock_status ) {
if ( $product->is_type( 'external' ) ) { if ( $product->is_type( 'external' ) ) {
// External products are always in stock. // External products are always in stock.
$product->set_stock_status( 'instock' ); $product->set_stock_status( 'instock' );
} elseif ( $product->is_type( 'variable' ) && ! $product->get_manage_stock() ) { } elseif ( isset( $stock_status ) ) {
// Stock status is determined by children. if ( $product->is_type( 'variable' ) && ! $product->get_manage_stock() ) {
foreach ( $product->get_children() as $child_id ) { // Stock status is determined by children.
$child = wc_get_product( $child_id ); foreach ( $product->get_children() as $child_id ) {
if ( ! $product->get_manage_stock() ) { $child = wc_get_product( $child_id );
$child->set_stock_status( $stock_status ); if ( ! $product->get_manage_stock() ) {
$child->save(); $child->set_stock_status( $stock_status );
$child->save();
}
} }
$product = WC_Product_Variable::sync( $product, false );
} else {
$product->set_stock_status( $stock_status );
} }
$product = WC_Product_Variable::sync( $product, false );
} else {
$product->set_stock_status( $stock_status );
} }
return $product; return $product;

View File

@ -140,7 +140,8 @@ defined( 'ABSPATH' ) || exit;
<select class="visibility" name="_visibility"> <select class="visibility" name="_visibility">
<?php <?php
$options = apply_filters( $options = apply_filters(
'woocommerce_product_visibility_options', array( 'woocommerce_product_visibility_options',
array(
'visible' => __( 'Catalog &amp; search', 'woocommerce' ), 'visible' => __( 'Catalog &amp; search', 'woocommerce' ),
'catalog' => __( 'Catalog', 'woocommerce' ), 'catalog' => __( 'Catalog', 'woocommerce' ),
'search' => __( 'Search', 'woocommerce' ), 'search' => __( 'Search', 'woocommerce' ),
@ -174,11 +175,15 @@ defined( 'ABSPATH' ) || exit;
<span class="input-text-wrap"> <span class="input-text-wrap">
<select class="stock_status" name="_stock_status"> <select class="stock_status" name="_stock_status">
<?php <?php
echo '<option value="" id="stock_status_no_change">' . esc_html__( '— No Change —', 'woocommerce' ) . '</option>';
foreach ( wc_get_product_stock_status_options() as $key => $value ) { foreach ( wc_get_product_stock_status_options() as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>'; echo '<option value="' . esc_attr( $key ) . '">' . esc_html( $value ) . '</option>';
} }
?> ?>
</select> </select>
<div class="quick-edit-warning" style="display:none">
<?php echo esc_html__( 'This will change the stock status of all variations.', 'woocommerce' ); ?></p>
</div>
</span> </span>
</label> </label>