2013-07-24 16:01:36 +00:00
< ? php
/**
2015-11-03 13:53:50 +00:00
* Duplicate product functionality
2013-07-24 16:01:36 +00:00
*
2014-11-30 06:52:32 +00:00
* @ author WooThemes
* @ category Admin
* @ package WooCommerce / Admin
2013-07-24 16:01:36 +00:00
* @ version 2.1 . 0
*/
2014-09-20 19:52:30 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
2013-07-24 16:01:36 +00:00
if ( ! class_exists ( 'WC_Admin_Duplicate_Product' ) ) :
/**
2015-11-03 12:28:01 +00:00
* WC_Admin_Duplicate_Product Class .
2013-07-24 16:01:36 +00:00
*/
class WC_Admin_Duplicate_Product {
/**
2015-11-03 12:28:01 +00:00
* Constructor .
2013-07-24 16:01:36 +00:00
*/
public function __construct () {
add_action ( 'admin_action_duplicate_product' , array ( $this , 'duplicate_product_action' ) );
add_filter ( 'post_row_actions' , array ( $this , 'dupe_link' ), 10 , 2 );
add_action ( 'post_submitbox_start' , array ( $this , 'dupe_button' ) );
}
/**
2015-11-03 12:28:01 +00:00
* Show the " Duplicate " link in admin products list .
2014-04-05 17:10:32 +00:00
* @ param array $actions
* @ param WP_Post $post Post object
2013-07-24 16:01:36 +00:00
* @ return array
*/
public function dupe_link ( $actions , $post ) {
2014-11-30 06:52:32 +00:00
if ( ! current_user_can ( apply_filters ( 'woocommerce_duplicate_product_capability' , 'manage_woocommerce' ) ) ) {
2013-07-24 16:01:36 +00:00
return $actions ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
2016-09-07 22:32:24 +00:00
if ( 'product' !== $post -> post_type ) {
2013-07-24 16:01:36 +00:00
return $actions ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
2016-11-04 15:41:51 +00:00
$actions [ 'duplicate' ] = '<a href="' . wp_nonce_url ( admin_url ( 'edit.php?post_type=product&action=duplicate_product&post=' . $post -> ID ), 'woocommerce-duplicate-product_' . $post -> ID ) . '" aria-label="' . esc_attr__ ( 'Make a duplicate from this product' , 'woocommerce' )
2016-09-01 20:50:14 +00:00
. '" rel="permalink">' . __ ( 'Duplicate' , 'woocommerce' ) . '</a>' ;
2013-07-24 16:01:36 +00:00
return $actions ;
}
/**
2015-11-03 12:28:01 +00:00
* Show the dupe product link in admin .
2013-07-24 16:01:36 +00:00
*/
public function dupe_button () {
global $post ;
2014-11-30 06:52:32 +00:00
if ( ! current_user_can ( apply_filters ( 'woocommerce_duplicate_product_capability' , 'manage_woocommerce' ) ) ) {
2013-12-02 11:34:27 +00:00
return ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
2014-11-30 06:52:32 +00:00
if ( ! is_object ( $post ) ) {
2013-07-24 16:01:36 +00:00
return ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
2016-09-07 22:32:24 +00:00
if ( 'product' !== $post -> post_type ) {
2013-07-24 16:01:36 +00:00
return ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
if ( isset ( $_GET [ 'post' ] ) ) {
2016-05-15 05:41:52 +00:00
$notify_url = wp_nonce_url ( admin_url ( " edit.php?post_type=product&action=duplicate_product&post= " . absint ( $_GET [ 'post' ] ) ), 'woocommerce-duplicate-product_' . $_GET [ 'post' ] );
2013-07-24 16:01:36 +00:00
?>
2016-05-15 05:41:52 +00:00
< div id = " duplicate-action " >< a class = " submitduplicate duplication " href = " <?php echo esc_url( $notify_url ); ?> " >< ? php _e ( 'Copy to a new draft' , 'woocommerce' ); ?> </a></div>
2013-07-24 16:01:36 +00:00
< ? php
}
}
/**
* Duplicate a product action .
*/
public function duplicate_product_action () {
2014-11-30 06:52:32 +00:00
2013-07-24 16:01:36 +00:00
if ( empty ( $_REQUEST [ 'post' ] ) ) {
2014-11-30 06:52:32 +00:00
wp_die ( __ ( 'No product to duplicate has been supplied!' , 'woocommerce' ) );
2013-07-24 16:01:36 +00:00
}
// Get the original page
$id = isset ( $_REQUEST [ 'post' ] ) ? absint ( $_REQUEST [ 'post' ] ) : '' ;
check_admin_referer ( 'woocommerce-duplicate-product_' . $id );
$post = $this -> get_product_to_duplicate ( $id );
// Copy the page and insert it
if ( ! empty ( $post ) ) {
$new_id = $this -> duplicate_product ( $post );
// If you have written a plugin which uses non-WP database tables to save
// information about a page you can hook this action to dupe that data.
do_action ( 'woocommerce_duplicate_product' , $new_id , $post );
// Redirect to the edit screen for the new draft page
wp_redirect ( admin_url ( 'post.php?action=edit&post=' . $new_id ) );
exit ;
} else {
2016-10-29 10:16:03 +00:00
/* translators: %s: product id */
2016-10-24 07:33:32 +00:00
wp_die ( sprintf ( __ ( 'Product creation failed, could not find original product: %s' , 'woocommerce' ), $id ) );
2013-07-24 16:01:36 +00:00
}
}
/**
* Function to create the duplicate of the product .
*
* @ param mixed $post
* @ param int $parent ( default : 0 )
* @ param string $post_status ( default : '' )
2013-11-27 09:03:47 +00:00
* @ return int
2013-07-24 16:01:36 +00:00
*/
public function duplicate_product ( $post , $parent = 0 , $post_status = '' ) {
global $wpdb ;
2014-11-30 06:52:32 +00:00
$new_post_author = wp_get_current_user ();
$new_post_date = current_time ( 'mysql' );
$new_post_date_gmt = get_gmt_from_date ( $new_post_date );
2013-07-24 16:01:36 +00:00
if ( $parent > 0 ) {
2016-07-14 12:54:39 +00:00
$post_parent = $parent ;
$post_status = $post_status ? $post_status : 'publish' ;
$suffix = '' ;
$post_title = $post -> post_title ;
2013-07-24 16:01:36 +00:00
} else {
2016-07-14 12:54:39 +00:00
$post_parent = $post -> post_parent ;
$post_status = $post_status ? $post_status : 'draft' ;
$suffix = ' ' . __ ( '(Copy)' , 'woocommerce' );
$post_title = $post -> post_title . $suffix ;
2013-07-24 16:01:36 +00:00
}
// Insert the new template in the post table
2014-09-29 05:26:03 +00:00
$wpdb -> insert (
2014-10-07 10:05:40 +00:00
$wpdb -> posts ,
array (
2014-11-30 06:52:32 +00:00
'post_author' => $new_post_author -> ID ,
'post_date' => $new_post_date ,
'post_date_gmt' => $new_post_date_gmt ,
2015-02-16 14:33:12 +00:00
'post_content' => $post -> post_content ,
'post_content_filtered' => $post -> post_content_filtered ,
2016-07-14 12:54:39 +00:00
'post_title' => $post_title ,
2015-02-16 14:33:12 +00:00
'post_excerpt' => $post -> post_excerpt ,
2014-11-30 06:52:32 +00:00
'post_status' => $post_status ,
2015-02-16 14:33:12 +00:00
'post_type' => $post -> post_type ,
'comment_status' => $post -> comment_status ,
'ping_status' => $post -> ping_status ,
2014-11-30 06:52:32 +00:00
'post_password' => $post -> post_password ,
'to_ping' => $post -> to_ping ,
'pinged' => $post -> pinged ,
'post_modified' => $new_post_date ,
'post_modified_gmt' => $new_post_date_gmt ,
'post_parent' => $post_parent ,
'menu_order' => $post -> menu_order ,
2016-08-27 01:46:45 +00:00
'post_mime_type' => $post -> post_mime_type ,
2014-10-07 10:05:40 +00:00
)
);
2013-07-24 16:01:36 +00:00
$new_post_id = $wpdb -> insert_id ;
2016-07-14 12:54:39 +00:00
// Set title for variations
if ( 'product_variation' === $post -> post_type ) {
2016-10-29 20:03:28 +00:00
/* translators: 1: variation id 2: product name */
2016-09-01 20:50:14 +00:00
$post_title = sprintf ( __ ( 'Variation #%1$s of %2$s' , 'woocommerce' ), absint ( $new_post_id ), esc_html ( get_the_title ( $post_parent ) ) );
2016-07-14 12:54:39 +00:00
$wpdb -> update (
$wpdb -> posts ,
array (
'post_title' => $post_title ,
),
array (
2016-08-27 01:46:45 +00:00
'ID' => $new_post_id ,
2016-07-14 12:54:39 +00:00
)
);
}
// Set name and GUID
if ( ! in_array ( $post_status , array ( 'draft' , 'pending' , 'auto-draft' ) ) ) {
$wpdb -> update (
$wpdb -> posts ,
array (
'post_name' => wp_unique_post_slug ( sanitize_title ( $post_title , $new_post_id ), $new_post_id , $post_status , $post -> post_type , $post_parent ),
'guid' => get_permalink ( $new_post_id ),
),
array (
2016-08-27 01:46:45 +00:00
'ID' => $new_post_id ,
2016-07-14 12:54:39 +00:00
)
);
}
2013-07-24 16:01:36 +00:00
// Copy the taxonomies
$this -> duplicate_post_taxonomies ( $post -> ID , $new_post_id , $post -> post_type );
// Copy the meta information
$this -> duplicate_post_meta ( $post -> ID , $new_post_id );
// Copy the children (variations)
2015-08-02 07:35:58 +00:00
$exclude = apply_filters ( 'woocommerce_duplicate_product_exclude_children' , false );
2013-07-24 16:01:36 +00:00
2015-06-09 11:07:26 +00:00
if ( ! $exclude && ( $children_products = get_children ( 'post_parent=' . $post -> ID . '&post_type=product_variation' ) ) ) {
foreach ( $children_products as $child ) {
$this -> duplicate_product ( $this -> get_product_to_duplicate ( $child -> ID ), $new_post_id , $child -> post_status );
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
}
2016-07-14 12:54:39 +00:00
// Clear cache
clean_post_cache ( $new_post_id );
2013-07-24 16:01:36 +00:00
return $new_post_id ;
}
/**
2015-11-03 12:28:01 +00:00
* Get a product from the database to duplicate .
2014-11-30 06:52:32 +00:00
*
2013-07-24 16:01:36 +00:00
* @ param mixed $id
2013-11-27 09:03:47 +00:00
* @ return WP_Post | bool
* @ todo Returning false ? Need to check for it in ...
* @ see duplicate_product
2013-07-24 16:01:36 +00:00
*/
private function get_product_to_duplicate ( $id ) {
global $wpdb ;
$id = absint ( $id );
2014-11-30 06:52:32 +00:00
if ( ! $id ) {
2013-07-24 16:01:36 +00:00
return false ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
$post = $wpdb -> get_results ( " SELECT * FROM $wpdb->posts WHERE ID= $id " );
2016-07-14 12:54:39 +00:00
if ( isset ( $post -> post_type ) && 'revision' === $post -> post_type ) {
2013-07-24 16:01:36 +00:00
$id = $post -> post_parent ;
$post = $wpdb -> get_results ( " SELECT * FROM $wpdb->posts WHERE ID= $id " );
}
2014-11-30 06:52:32 +00:00
2013-07-24 16:01:36 +00:00
return $post [ 0 ];
}
/**
2015-11-03 12:28:01 +00:00
* Copy the taxonomies of a post to another post .
2013-07-24 16:01:36 +00:00
*
* @ param mixed $id
* @ param mixed $new_id
* @ param mixed $post_type
*/
private function duplicate_post_taxonomies ( $id , $new_id , $post_type ) {
2015-06-09 11:07:26 +00:00
$exclude = array_filter ( apply_filters ( 'woocommerce_duplicate_product_exclude_taxonomies' , array () ) );
$taxonomies = array_diff ( get_object_taxonomies ( $post_type ), $exclude );
2014-11-30 06:52:32 +00:00
foreach ( $taxonomies as $taxonomy ) {
2015-06-09 11:07:26 +00:00
$post_terms = wp_get_object_terms ( $id , $taxonomy );
2013-07-24 16:01:36 +00:00
$post_terms_count = sizeof ( $post_terms );
2014-11-30 06:52:32 +00:00
2015-06-09 11:07:26 +00:00
for ( $i = 0 ; $i < $post_terms_count ; $i ++ ) {
wp_set_object_terms ( $new_id , $post_terms [ $i ] -> slug , $taxonomy , true );
2013-07-24 16:01:36 +00:00
}
}
}
/**
2015-11-03 12:28:01 +00:00
* Copy the meta information of a post to another post .
2013-07-24 16:01:36 +00:00
*
* @ param mixed $id
* @ param mixed $new_id
*/
private function duplicate_post_meta ( $id , $new_id ) {
global $wpdb ;
2015-03-05 10:03:25 +00:00
2015-08-07 10:37:15 +00:00
$sql = $wpdb -> prepare ( " SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id = %d " , absint ( $id ) );
2016-04-21 13:03:20 +00:00
$exclude = array_map ( 'esc_sql' , array_filter ( apply_filters ( 'woocommerce_duplicate_product_exclude_meta' , array ( 'total_sales' , '_wc_average_rating' , '_wc_rating_count' , '_wc_review_count' , '_sku' ) ) ) );
2014-11-30 06:52:32 +00:00
2015-06-09 11:07:26 +00:00
if ( sizeof ( $exclude ) ) {
2015-08-07 10:37:15 +00:00
$sql .= " AND meta_key NOT IN ( ' " . implode ( " ',' " , $exclude ) . " ' ) " ;
2015-06-09 11:07:26 +00:00
}
2013-07-24 16:01:36 +00:00
2015-08-07 10:37:15 +00:00
$post_meta = $wpdb -> get_results ( $sql );
2015-11-03 12:28:01 +00:00
2015-06-09 11:07:26 +00:00
if ( sizeof ( $post_meta ) ) {
2014-04-05 17:16:46 +00:00
$sql_query_sel = array ();
2015-06-09 11:07:26 +00:00
$sql_query = " INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) " ;
2014-11-30 06:52:32 +00:00
2015-06-09 11:07:26 +00:00
foreach ( $post_meta as $post_meta_row ) {
$sql_query_sel [] = $wpdb -> prepare ( " SELECT %d, %s, %s " , $new_id , $post_meta_row -> meta_key , $post_meta_row -> meta_value );
2013-07-24 16:01:36 +00:00
}
2014-11-30 06:52:32 +00:00
2015-06-09 11:07:26 +00:00
$sql_query .= implode ( " UNION ALL " , $sql_query_sel );
$wpdb -> query ( $sql_query );
2013-07-24 16:01:36 +00:00
}
}
}
endif ;
2013-12-02 11:34:27 +00:00
return new WC_Admin_Duplicate_Product ();