Merge pull request #22067 from Prospress/fix/22046

populate default variation attributes when it is the first variation
This commit is contained in:
Mike Jolley 2019-01-22 17:29:54 +00:00 committed by GitHub
commit 43ba62dc86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 87 additions and 40 deletions

View File

@ -12,7 +12,7 @@ if ( ! defined( 'ABSPATH' ) ) {
/**
* WC Variable Product Data Store: Stored in CPT.
*
* @version 3.0.0
* @version 3.0.0
*/
class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT implements WC_Object_Data_Store_Interface, WC_Product_Variable_Data_Store_Interface {
@ -96,9 +96,9 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
/**
* Read product data.
*
* @since 3.0.0
*
* @param WC_Product $product Product object.
*
* @since 3.0.0
*/
protected function read_product_data( &$product ) {
parent::read_product_data( $product );
@ -111,8 +111,9 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
/**
* Loads variation child IDs.
*
* @param WC_Product $product Product object.
* @param bool $force_read True to bypass the transient.
* @param WC_Product $product Product object.
* @param bool $force_read True to bypass the transient.
*
* @return array
*/
public function read_children( &$product, $force_read = false ) {
@ -159,6 +160,7 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
* Loads an array of attributes used for variations, as well as their possible values.
*
* @param WC_Product $product Product object.
*
* @return array
*/
public function read_variation_attributes( &$product ) {
@ -175,22 +177,28 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
return $cached_data;
}
if ( ! empty( $child_ids ) && ! empty( $attributes ) ) {
if ( ! empty( $attributes ) ) {
foreach ( $attributes as $attribute ) {
if ( empty( $attribute['is_variation'] ) ) {
continue;
}
// Get possible values for this attribute, for only visible variations.
$values = array_unique(
$wpdb->get_col(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
"SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id IN (" . implode( ',', array_map( 'absint', $child_ids ) ) . ')',
wc_variation_attribute_name( $attribute['name'] )
if ( ! empty( $child_ids ) ) {
$format = array_fill( 0, count( $child_ids ), '%d' );
$query_in = '(' . implode( ',', $format ) . ')';
$query_args = array( 'attribute_name' => wc_variation_attribute_name( $attribute['name'] ) ) + $child_ids;
$values = array_unique(
$wpdb->get_col(
$wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
"SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id IN {$query_in}", // @codingStandardsIgnoreLine.
$query_args
)
)
)
);
);
} else {
$values = array();
}
// Empty value indicates that all options for given attribute are available.
if ( in_array( null, $values, true ) || in_array( '', $values, true ) || empty( $values ) ) {
@ -232,10 +240,11 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
* Can be filtered by plugins which modify costs, but otherwise will include the raw meta costs unlike get_price() which runs costs through the woocommerce_get_price filter.
* This is to ensure modified prices are not cached, unless intended.
*
* @since 3.0.0
* @param WC_Product $product Product object.
* @param bool $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes).
* @param WC_Product $product Product object.
* @param bool $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes).
*
* @return array of prices
* @since 3.0.0
*/
public function read_price_data( &$product, $for_display = false ) {
@ -363,9 +372,10 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
* Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
* DEVELOPERS should filter this hash if offering conditional pricing to keep it unique.
*
* @param WC_Product $product Product object.
* @param bool $for_display If taxes should be calculated or not.
*
* @since 3.0.0
* @param WC_Product $product Product object.
* @param bool $for_display If taxes should be calculated or not.
* @return string
*/
protected function get_price_hash( &$product, $for_display = false ) {
@ -397,34 +407,51 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
/**
* Does a child have a weight set?
*
* @since 3.0.0
* @param WC_Product $product Product object.
*
* @since 3.0.0
* @return boolean
*/
public function child_has_weight( $product ) {
global $wpdb;
$children = $product->get_visible_children();
return $children ? null !== $wpdb->get_var( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_weight' AND meta_value > 0 AND post_id IN ( " . implode( ',', array_map( 'absint', $children ) ) . ' )' ) : false; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( ! $children ) {
return false;
}
$format = array_fill( 0, count( $children ), '%d' );
$query_in = '(' . implode( ',', $format ) . ')';
return null !== $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_weight' AND meta_value > 0 AND post_id IN {$query_in}", $children ) ); // @codingStandardsIgnoreLine.
}
/**
* Does a child have dimensions set?
*
* @since 3.0.0
* @param WC_Product $product Product object.
*
* @since 3.0.0
* @return boolean
*/
public function child_has_dimensions( $product ) {
global $wpdb;
$children = $product->get_visible_children();
return $children ? null !== $wpdb->get_var( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key IN ( '_length', '_width', '_height' ) AND meta_value > 0 AND post_id IN ( " . implode( ',', array_map( 'absint', $children ) ) . ' )' ) : false; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( ! $children ) {
return false;
}
$format = array_fill( 0, count( $children ), '%d' );
$query_in = '(' . implode( ',', $format ) . ')';
return null !== $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key IN ( '_length', '_width', '_height' ) AND meta_value > 0 AND post_id IN {$query_in}", $children ) ); // @codingStandardsIgnoreLine.
}
/**
* Is a child in stock?
*
* @since 3.0.0
* @param WC_Product $product Product object.
*
* @since 3.0.0
* @return boolean
*/
public function child_is_in_stock( $product ) {
@ -434,9 +461,10 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
/**
* Does a child have a stock status?
*
* @since 3.3.0
* @param WC_Product $product Product object.
* @param string $status 'instock', 'outofstock', or 'onbackorder'.
*
* @since 3.3.0
* @return boolean
*/
public function child_has_stock_status( $product, $status ) {
@ -445,11 +473,13 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
$children = $product->get_children();
if ( $children ) {
$format = array_fill( 0, count( $children ), '%d' );
$query_in = '(' . implode( ',', $format ) . ')';
$query_args = array( 'stock_status' => $status ) + $children;
$children_with_status = $wpdb->get_var(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
"SELECT COUNT( post_id ) FROM $wpdb->postmeta WHERE meta_key = '_stock_status' AND meta_value = %s AND post_id IN ( " . implode( ',', array_map( 'absint', $children ) ) . ' )',
$status
$wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
"SELECT COUNT( post_id ) FROM $wpdb->postmeta WHERE meta_key = '_stock_status' AND meta_value = %s AND post_id IN {$query_in}", // @codingStandardsIgnoreLine.
$query_args
)
);
} else {
@ -465,6 +495,7 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
* @param WC_Product $product Product object.
* @param string $previous_name Variation previous name.
* @param string $new_name Variation new name.
*
* @since 3.0.0
*/
public function sync_variation_names( &$product, $previous_name = '', $new_name = '' ) {
@ -490,21 +521,28 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
* This sync function syncs downwards (from parent to child) when the variable product is saved.
*
* @param WC_Product $product Product object.
*
* @since 3.0.0
*/
public function sync_managed_variation_stock_status( &$product ) {
global $wpdb;
if ( $product->get_manage_stock() ) {
$status = $product->get_stock_status();
$children = $product->get_children();
$managed_children = $children ? array_unique( $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_manage_stock' AND meta_value != 'yes' AND post_id IN ( " . implode( ',', array_map( 'absint', $children ) ) . ' )' ) ) : array(); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$changed = false;
foreach ( $managed_children as $managed_child ) {
if ( update_post_meta( $managed_child, '_stock_status', $status ) ) {
$changed = true;
$children = $product->get_children();
$changed = false;
if ( $children ) {
$status = $product->get_stock_status();
$format = array_fill( 0, count( $children ), '%d' );
$query_in = '(' . implode( ',', $format ) . ')';
$managed_children = array_unique( $wpdb->get_col( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_manage_stock' AND meta_value != 'yes' AND post_id IN {$query_in}", $children ) ) ); // @codingStandardsIgnoreLine.
foreach ( $managed_children as $managed_child ) {
if ( update_post_meta( $managed_child, '_stock_status', $status ) ) {
$changed = true;
}
}
}
if ( $changed ) {
$children = $this->read_children( $product, true );
$product->set_children( $children['all'] );
@ -516,14 +554,21 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
/**
* Sync variable product prices with children.
*
* @since 3.0.0
* @param WC_Product $product Product object.
*
* @since 3.0.0
*/
public function sync_price( &$product ) {
global $wpdb;
$children = $product->get_visible_children();
$prices = $children ? array_unique( $wpdb->get_col( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key = '_price' AND post_id IN ( " . implode( ',', array_map( 'absint', $children ) ) . ' )' ) ) : array(); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
if ( $children ) {
$format = array_fill( 0, count( $children ), '%d' );
$query_in = '(' . implode( ',', $format ) . ')';
$prices = array_unique( $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key = '_price' AND post_id IN {$query_in}", $children ) ) ); // @codingStandardsIgnoreLine.
} else {
$prices = array();
}
delete_post_meta( $product->get_id(), '_price' );
delete_post_meta( $product->get_id(), '_sale_price' );
@ -545,8 +590,9 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
* Sync variable product stock status with children.
* Change does not persist unless saved by caller.
*
* @since 3.0.0
* @param WC_Product $product Product object.
*
* @since 3.0.0
*/
public function sync_stock_status( &$product ) {
if ( $product->child_is_in_stock() ) {
@ -561,9 +607,10 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
/**
* Delete variations of a product.
*
* @since 3.0.0
* @param int $product_id Product ID.
* @param bool $force_delete False to trash.
*
* @since 3.0.0
*/
public function delete_variations( $product_id, $force_delete = false ) {
if ( ! is_numeric( $product_id ) || 0 >= $product_id ) {