Merge pull request #13202 from woocommerce/fix-13199
Duplicate products; fix variation creation and add actions
This commit is contained in:
commit
2505abeb21
|
@ -94,32 +94,50 @@ class WC_Admin_Duplicate_Product {
|
|||
wp_die( sprintf( __( 'Product creation failed, could not find original product: %s', 'woocommerce' ), $product_id ) );
|
||||
}
|
||||
|
||||
// Filter to allow us to unset/remove data we don't want to copy to the duplicate. @since 2.6
|
||||
$meta_to_exclude = array_filter( apply_filters( 'woocommerce_duplicate_product_exclude_meta', array() ) );
|
||||
|
||||
$duplicate = clone $product;
|
||||
$duplicate->set_id( 0 );
|
||||
$duplicate->save();
|
||||
$duplicate->set_total_sales( 0 );
|
||||
if ( '' !== $product->get_sku() ) {
|
||||
$duplicate->set_sku( wc_product_generate_unique_sku( 0, $product->get_sku() ) );
|
||||
}
|
||||
$duplicate->set_status( 'draft' );
|
||||
|
||||
$sku = $duplicate->get_sku();
|
||||
if ( '' !== $duplicate->get_sku() ) {
|
||||
wc_product_force_unique_sku( $duplicate->get_id() );
|
||||
foreach ( $meta_to_exclude as $meta_key ) {
|
||||
$duplicate->delete_meta_data( $meta_key );
|
||||
}
|
||||
|
||||
$exclude = apply_filters( 'woocommerce_duplicate_product_exclude_children', false );
|
||||
// This action can be used to modify the object further before it is created - it will be passed by reference. @since 2.7
|
||||
do_action( 'woocommerce_product_duplicate_before_save', $duplicate, $product );
|
||||
|
||||
if ( ! $exclude && ( $product->is_type( 'variable' ) || $product->is_type( 'grouped' ) ) ) {
|
||||
// Save parent product.
|
||||
$duplicate->save();
|
||||
|
||||
if ( ! apply_filters( 'woocommerce_duplicate_product_exclude_children', false ) && ( $product->is_type( 'variable' ) || $product->is_type( 'grouped' ) ) ) {
|
||||
foreach ( $product->get_children() as $child_id ) {
|
||||
$child = wc_get_product( $child_id );
|
||||
$child_duplicate = clone $child;
|
||||
$child_duplicate->set_parent_id( $duplicate->get_id() );
|
||||
$child_duplicate->set_id( 0 );
|
||||
$child_duplicate->save();
|
||||
if ( '' !== $child_duplicate->get_sku() ) {
|
||||
wc_product_force_unique_sku( $child_duplicate->get_id() );
|
||||
|
||||
if ( '' !== $child->get_sku() ) {
|
||||
$child_duplicate->set_sku( wc_product_generate_unique_sku( 0, $child->get_sku() ) );
|
||||
}
|
||||
|
||||
foreach ( $meta_to_exclude as $meta_key ) {
|
||||
$child_duplicate->delete_meta_data( $meta_key );
|
||||
}
|
||||
|
||||
// This action can be used to modify the object further before it is created - it will be passed by reference. @since 2.7
|
||||
do_action( 'woocommerce_product_duplicate_before_save', $child_duplicate, $child );
|
||||
|
||||
$child_duplicate->save();
|
||||
}
|
||||
}
|
||||
|
||||
// Hook rename to match other woocommerce_product_* hooks, and to move away from depending on a response from the wp_posts table.
|
||||
// New hook returns new id and old id.
|
||||
do_action( 'woocommerce_product_duplicate', $duplicate, $product );
|
||||
wc_do_deprecated_action( 'woocommerce_duplicate_product', array( $duplicate->get_id(), $this->get_product_to_duplicate( $product_id ) ), '2.7', 'Use woocommerce_product_duplicate action instead.' );
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
@ -162,24 +160,22 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
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_content' => $product->get_description(),
|
||||
'post_excerpt' => $product->get_short_description(),
|
||||
'post_title' => $product->get_name(),
|
||||
'post_parent' => $product->get_parent_id(),
|
||||
'comment_status' => $product->get_reviews_allowed() ? 'open' : 'closed',
|
||||
'post_status' => $product->get_status() ? $product->get_status() : 'publish',
|
||||
'menu_order' => $product->get_menu_order(),
|
||||
'post_content' => $product->get_description( 'edit' ),
|
||||
'post_excerpt' => $product->get_short_description( 'edit' ),
|
||||
'post_title' => $product->get_name( 'edit' ),
|
||||
'post_parent' => $product->get_parent_id( 'edit' ),
|
||||
'comment_status' => $product->get_reviews_allowed( 'edit' ) ? 'open' : 'closed',
|
||||
'post_status' => $product->get_status( 'edit' ) ? $product->get_status( 'edit' ) : 'publish',
|
||||
'menu_order' => $product->get_menu_order( 'edit' ),
|
||||
) );
|
||||
}
|
||||
|
||||
$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();
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,25 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
|
|||
* @param WC_Product
|
||||
*/
|
||||
public function update( &$product ) {
|
||||
$post_data = array(
|
||||
$changes = $product->get_changes();
|
||||
$title = $this->generate_product_title( $product );
|
||||
|
||||
// Only update the post when the post data changes.
|
||||
if ( $title !== $product->get_name( 'edit' ) || array_intersect( array( 'parent_id', '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(),
|
||||
'post_title' => $title,
|
||||
'post_parent' => $product->get_parent_id( 'edit' ),
|
||||
'comment_status' => 'closed',
|
||||
'post_status' => $product->get_status() ? $product->get_status() : 'publish',
|
||||
'menu_order' => $product->get_menu_order(),
|
||||
);
|
||||
'post_status' => $product->get_status( 'edit' ) ? $product->get_status( 'edit' ) : 'publish',
|
||||
'menu_order' => $product->get_menu_order( 'edit' ),
|
||||
) );
|
||||
}
|
||||
|
||||
wp_update_post( $post_data );
|
||||
|
||||
$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,18 +283,27 @@ 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 ) {
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update attribute meta values.
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @param WC_Product
|
||||
* @param bool Force update. Used during create.
|
||||
*/
|
||||
protected function update_attributes( &$product ) {
|
||||
protected function update_attributes( &$product, $force = false ) {
|
||||
$changes = $product->get_changes();
|
||||
|
||||
if ( $force || array_key_exists( 'attributes', $changes ) ) {
|
||||
global $wpdb;
|
||||
$attributes = $product->get_attributes();
|
||||
$updated_attribute_keys = array();
|
||||
|
@ -310,18 +319,28 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
|
|||
delete_post_meta( $product->get_id(), $key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that updates all the post meta for a product based on it's settings in the WC_Product class.
|
||||
*
|
||||
* @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 );
|
||||
|
|
Loading…
Reference in New Issue