Standardise update meta calls, and support forcing

Force allows create to make sure data is set regardless of whether it
was changed. This fixes product duplication.

Fixes #13199
This commit is contained in:
Mike Jolley 2017-02-15 14:40:57 +00:00
parent 019b2515b8
commit 2f685691a4
3 changed files with 111 additions and 67 deletions

View File

@ -98,14 +98,12 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
if ( $id && ! is_wp_error( $id ) ) {
$product->set_id( $id );
$this->updated_props = array();
$this->update_post_meta( $product );
$this->handle_updated_props( $product );
$this->update_terms( $product );
$this->update_visibility( $product );
$this->update_attributes( $product );
$this->update_post_meta( $product, true );
$this->update_terms( $product, true );
$this->update_visibility( $product, true );
$this->update_attributes( $product, true );
$this->update_version_and_type( $product );
$this->handle_updated_props( $product );
$product->save_meta_data();
$product->apply_changes();
@ -172,14 +170,12 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
) );
}
$this->updated_props = array();
$this->update_post_meta( $product );
$this->handle_updated_props( $product );
$this->update_terms( $product );
$this->update_visibility( $product );
$this->update_attributes( $product );
$this->update_version_and_type( $product );
$this->handle_updated_props( $product );
$product->save_meta_data();
$product->apply_changes();
@ -385,10 +381,10 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
* Helper method that updates all the post meta for a product based on it's settings in the WC_Product class.
*
* @param WC_Product
* @param bool Force update. Used during create.
* @since 2.7.0
*/
protected function update_post_meta( &$product ) {
protected function update_post_meta( &$product, $force = false ) {
$meta_key_to_props = array(
'_sku' => 'sku',
'_regular_price' => 'regular_price',
@ -424,11 +420,12 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
// Make sure to take extra data (like product url or text for external products) into account.
$extra_data_keys = $product->get_extra_data_keys();
foreach ( $extra_data_keys as $key ) {
$meta_key_to_props[ '_' . $key ] = $key;
}
$props_to_update = $this->get_props_to_update( $product, $meta_key_to_props );
$props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $product, $meta_key_to_props );
foreach ( $props_to_update as $meta_key => $prop ) {
$value = $product->{"get_$prop"}( 'edit' );
@ -474,19 +471,18 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
}
}
if ( $this->update_downloads( $product ) ) {
if ( $this->update_downloads( $product, $force ) ) {
$this->updated_props[] = 'downloads';
}
}
/**
* Handle updated meta props after updating meta.
* Handle updated meta props after updating meta data.
*
* @since 2.7.0
* @param WC_Product $product
*/
protected function handle_updated_props( &$product ) {
if ( in_array( 'date_on_sale_from', $this->updated_props ) || in_array( 'date_on_sale_to', $this->updated_props ) || in_array( 'regular_price', $this->updated_props ) || in_array( 'sale_price', $this->updated_props ) ) {
if ( $product->is_on_sale( 'edit' ) ) {
update_post_meta( $product->get_id(), '_price', $product->get_sale_price( 'edit' ) );
@ -505,25 +501,30 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
do_action( $product->is_type( 'variation' ) ? 'woocommerce_variation_set_stock_status' : 'woocommerce_product_set_stock_status' , $product->get_id(), $product->get_stock_status(), $product );
}
// Trigger action so 3rd parties can deal with updated props.
do_action( 'woocommerce_product_object_updated_props', $product, $this->updated_props );
// After handling, we can reset the props array.
$this->updated_props = array();
}
/**
* For all stored terms in all taxonomies, save them to the DB.
*
* @param WC_Product
* @param bool Force update. Used during create.
* @since 2.7.0
*/
protected function update_terms( &$product ) {
protected function update_terms( &$product, $force = false ) {
$changes = $product->get_changes();
if ( array_key_exists( 'category_ids', $changes ) ) {
if ( $force || array_key_exists( 'category_ids', $changes ) ) {
wp_set_post_terms( $product->get_id(), $product->get_category_ids( 'edit' ), 'product_cat', false );
}
if ( array_key_exists( 'tag_ids', $changes ) ) {
if ( $force || array_key_exists( 'tag_ids', $changes ) ) {
wp_set_post_terms( $product->get_id(), $product->get_tag_ids( 'edit' ), 'product_tag', false );
}
if ( array_key_exists( 'shipping_class_id', $changes ) ) {
if ( $force || array_key_exists( 'shipping_class_id', $changes ) ) {
wp_set_post_terms( $product->get_id(), array( $product->get_shipping_class_id( 'edit' ) ), 'product_shipping_class', false );
}
}
@ -532,12 +533,13 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
* Update visibility terms based on props.
*
* @since 2.7.0
* @param bool Force update. Used during create.
* @param WC_Product
*/
protected function update_visibility( &$product ) {
protected function update_visibility( &$product, $force = false ) {
$changes = $product->get_changes();
if ( array_intersect( array( 'featured', 'stock_status', 'average_rating', 'catalog_visibility' ), array_keys( $changes ) ) ) {
if ( $force || array_intersect( array( 'featured', 'stock_status', 'average_rating', 'catalog_visibility' ), array_keys( $changes ) ) ) {
$terms = array();
if ( $product->get_featured() ) {
@ -575,12 +577,13 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
* Update attributes which are a mix of terms and meta data.
*
* @param WC_Product
* @param bool Force update. Used during create.
* @since 2.7.0
*/
protected function update_attributes( &$product ) {
protected function update_attributes( &$product, $force = false ) {
$changes = $product->get_changes();
if ( array_key_exists( 'attributes', $changes ) ) {
if ( $force || array_key_exists( 'attributes', $changes ) ) {
$attributes = $product->get_attributes();
$meta_values = array();
@ -622,12 +625,13 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
*
* @since 2.7.0
* @param WC_Product $product
* @param bool Force update. Used during create.
* @return bool If updated or not.
*/
protected function update_downloads( &$product ) {
protected function update_downloads( &$product, $force = false ) {
$changes = $product->get_changes();
if ( array_key_exists( 'downloads', $changes ) ) {
if ( $force || array_key_exists( 'downloads', $changes ) ) {
$downloads = $product->get_downloads();
$meta_values = array();

View File

@ -16,10 +16,35 @@ class WC_Product_Grouped_Data_Store_CPT extends WC_Product_Data_Store_CPT implem
* Helper method that updates all the post meta for a grouped product.
*
* @param WC_Product
* @param bool Force update. Used during create.
* @since 2.7.0
*/
protected function update_post_meta( &$product ) {
if ( update_post_meta( $product->get_id(), '_children', $product->get_children( 'edit' ) ) ) {
protected function update_post_meta( &$product, $force = false ) {
$meta_key_to_props = array(
'_children' => 'children',
);
$props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $product, $meta_key_to_props );
foreach ( $props_to_update as $meta_key => $prop ) {
$value = $product->{"get_$prop"}( 'edit' );
$updated = update_post_meta( $product->get_id(), $meta_key, $value );
if ( $updated ) {
$this->updated_props[] = $prop;
}
}
parent::update_post_meta( $product );
}
/**
* Handle updated meta props after updating meta data.
*
* @since 2.7.0
* @param WC_Product $product
*/
protected function handle_updated_props( &$product ) {
if ( in_array( 'children', $this->updated_props ) ) {
$child_prices = array();
foreach ( $product->get_children( 'edit' ) as $child_id ) {
$child = wc_get_product( $child_id );
@ -34,11 +59,8 @@ class WC_Product_Grouped_Data_Store_CPT extends WC_Product_Data_Store_CPT implem
add_post_meta( $product->get_id(), '_price', min( $child_prices ) );
add_post_meta( $product->get_id(), '_price', max( $child_prices ) );
}
$this->extra_data_saved = true;
}
parent::update_post_meta( $product );
parent::handle_updated_props( $product );
}
/**

View File

@ -113,13 +113,11 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
if ( $id && ! is_wp_error( $id ) ) {
$product->set_id( $id );
$this->updated_props = array();
$this->update_post_meta( $product );
$this->update_post_meta( $product, true );
$this->update_terms( $product, true );
$this->update_attributes( $product, true );
$this->handle_updated_props( $product );
$this->update_terms( $product );
$this->update_attributes( $product );
$product->save_meta_data();
$product->apply_changes();
@ -138,23 +136,24 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
* @param WC_Product
*/
public function update( &$product ) {
$post_data = array(
'ID' => $product->get_id(),
'post_title' => $this->generate_product_title( $product ),
'post_parent' => $product->get_parent_id(),
'comment_status' => 'closed',
'post_status' => $product->get_status() ? $product->get_status() : 'publish',
'menu_order' => $product->get_menu_order(),
);
$changes = $product->get_changes();
wp_update_post( $post_data );
// Only update the post when the post data changes.
if ( array_intersect( array( 'description', 'short_description', 'name', 'parent_id', 'reviews_allowed', 'status', 'menu_order' ), array_keys( $changes ) ) ) {
wp_update_post( array(
'ID' => $product->get_id(),
'post_title' => $this->generate_product_title( $product ), // !
'post_parent' => $product->get_parent_id(),
'comment_status' => 'closed',
'post_status' => $product->get_status() ? $product->get_status() : 'publish',
'menu_order' => $product->get_menu_order(),
) );
}
$this->updated_props = array();
$this->update_post_meta( $product );
$this->handle_updated_props( $product );
$this->update_terms( $product );
$this->update_attributes( $product );
$this->handle_updated_props( $product );
$product->save_meta_data();
$product->apply_changes();
@ -283,9 +282,14 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
*
* @since 2.7.0
* @param WC_Product
* @param bool Force update. Used during create.
*/
protected function update_terms( &$product ) {
wp_set_post_terms( $product->get_id(), array( $product->get_shipping_class_id( 'edit' ) ), 'product_shipping_class', false );
protected function update_terms( &$product, $force = false ) {
$changes = $product->get_changes();
if ( $force || array_key_exists( 'shipping_class_id', $changes ) ) {
wp_set_post_terms( $product->get_id(), array( $product->get_shipping_class_id( 'edit' ) ), 'product_shipping_class', false );
}
}
/**
@ -293,21 +297,26 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
*
* @since 2.7.0
* @param WC_Product
* @param bool Force update. Used during create.
*/
protected function update_attributes( &$product ) {
global $wpdb;
$attributes = $product->get_attributes();
$updated_attribute_keys = array();
foreach ( $attributes as $key => $value ) {
update_post_meta( $product->get_id(), 'attribute_' . $key, $value );
$updated_attribute_keys[] = 'attribute_' . $key;
}
protected function update_attributes( &$product, $force = false ) {
$changes = $product->get_changes();
// Remove old taxonomies attributes so data is kept up to date - first get attribute key names.
$delete_attribute_keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->postmeta} WHERE meta_key LIKE 'attribute_%%' AND meta_key NOT IN ( '" . implode( "','", array_map( 'esc_sql', $updated_attribute_keys ) ) . "' ) AND post_id = %d;", $product->get_id() ) );
if ( $force || array_key_exists( 'attributes', $changes ) ) {
global $wpdb;
$attributes = $product->get_attributes();
$updated_attribute_keys = array();
foreach ( $attributes as $key => $value ) {
update_post_meta( $product->get_id(), 'attribute_' . $key, $value );
$updated_attribute_keys[] = 'attribute_' . $key;
}
foreach ( $delete_attribute_keys as $key ) {
delete_post_meta( $product->get_id(), $key );
// Remove old taxonomies attributes so data is kept up to date - first get attribute key names.
$delete_attribute_keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->postmeta} WHERE meta_key LIKE 'attribute_%%' AND meta_key NOT IN ( '" . implode( "','", array_map( 'esc_sql', $updated_attribute_keys ) ) . "' ) AND post_id = %d;", $product->get_id() ) );
foreach ( $delete_attribute_keys as $key ) {
delete_post_meta( $product->get_id(), $key );
}
}
}
@ -316,12 +325,21 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
*
* @since 2.7.0
* @param WC_Product
* @param bool Force update. Used during create.
*/
public function update_post_meta( &$product ) {
$updated_description = update_post_meta( $product->get_id(), '_variation_description', $product->get_description() );
public function update_post_meta( &$product, $force = false ) {
$meta_key_to_props = array(
'_variation_description' => 'description',
);
if ( $updated_description ) {
$this->updated_props[] = 'description';
$props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $product, $meta_key_to_props );
foreach ( $props_to_update as $meta_key => $prop ) {
$value = $product->{"get_$prop"}( 'edit' );
$updated = update_post_meta( $product->get_id(), $meta_key, $value );
if ( $updated ) {
$this->updated_props[] = $prop;
}
}
parent::update_post_meta( $product );