WC_Admin_Duplicate_Product

WC_Admin_Duplicate_Product Class.

Defined (1)

The class is defined in the following location(s).

/includes/admin/class-wc-admin-duplicate-product.php  
  1. class WC_Admin_Duplicate_Product { 
  2.  
  3. /** 
  4. * Constructor. 
  5. */ 
  6. public function __construct() { 
  7. add_action( 'admin_action_duplicate_product', array( $this, 'duplicate_product_action' ) ); 
  8. add_filter( 'post_row_actions', array( $this, 'dupe_link' ), 10, 2 ); 
  9. add_action( 'post_submitbox_start', array( $this, 'dupe_button' ) ); 
  10.  
  11. /** 
  12. * Show the "Duplicate" link in admin products list. 
  13. * @param array $actions 
  14. * @param WP_Post $post Post object 
  15. * @return array 
  16. */ 
  17. public function dupe_link( $actions, $post ) { 
  18. if ( ! current_user_can( apply_filters( 'woocommerce_duplicate_product_capability', 'manage_woocommerce' ) ) ) { 
  19. return $actions; 
  20.  
  21. if ( $post->post_type != 'product' ) { 
  22. return $actions; 
  23.  
  24. $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 ) . '" title="' . esc_attr__( 'Make a duplicate from this product', 'woocommerce' ) 
  25. . '" rel="permalink">' . __( 'Duplicate', 'woocommerce' ) . '</a>'; 
  26.  
  27. return $actions; 
  28.  
  29. /** 
  30. * Show the dupe product link in admin. 
  31. */ 
  32. public function dupe_button() { 
  33. global $post; 
  34.  
  35. if ( ! current_user_can( apply_filters( 'woocommerce_duplicate_product_capability', 'manage_woocommerce' ) ) ) { 
  36. return; 
  37.  
  38. if ( ! is_object( $post ) ) { 
  39. return; 
  40.  
  41. if ( $post->post_type != 'product' ) { 
  42. return; 
  43.  
  44. if ( isset( $_GET['post'] ) ) { 
  45. $notify_url = wp_nonce_url( admin_url( "edit.php?post_type=product&action=duplicate_product&post=" . absint( $_GET['post'] ) ), 'woocommerce-duplicate-product_' . $_GET['post'] ); 
  46. ?> 
  47. <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> 
  48. <?php 
  49.  
  50. /** 
  51. * Duplicate a product action. 
  52. */ 
  53. public function duplicate_product_action() { 
  54.  
  55. if ( empty( $_REQUEST['post'] ) ) { 
  56. wp_die( __( 'No product to duplicate has been supplied!', 'woocommerce' ) ); 
  57.  
  58. // Get the original page 
  59. $id = isset( $_REQUEST['post'] ) ? absint( $_REQUEST['post'] ) : ''; 
  60.  
  61. check_admin_referer( 'woocommerce-duplicate-product_' . $id ); 
  62.  
  63. $post = $this->get_product_to_duplicate( $id ); 
  64.  
  65. // Copy the page and insert it 
  66. if ( ! empty( $post ) ) { 
  67. $new_id = $this->duplicate_product( $post ); 
  68.  
  69. // If you have written a plugin which uses non-WP database tables to save 
  70. // information about a page you can hook this action to dupe that data. 
  71. do_action( 'woocommerce_duplicate_product', $new_id, $post ); 
  72.  
  73. // Redirect to the edit screen for the new draft page 
  74. wp_redirect( admin_url( 'post.php?action=edit&post=' . $new_id ) ); 
  75. exit; 
  76. } else { 
  77. wp_die( __( 'Product creation failed, could not find original product:', 'woocommerce' ) . ' ' . $id ); 
  78.  
  79. /** 
  80. * Function to create the duplicate of the product. 
  81. * @param mixed $post 
  82. * @param int $parent (default: 0) 
  83. * @param string $post_status (default: '') 
  84. * @return int 
  85. */ 
  86. public function duplicate_product( $post, $parent = 0, $post_status = '' ) { 
  87. global $wpdb; 
  88.  
  89. $new_post_author = wp_get_current_user(); 
  90. $new_post_date = current_time( 'mysql' ); 
  91. $new_post_date_gmt = get_gmt_from_date( $new_post_date ); 
  92.  
  93. if ( $parent > 0 ) { 
  94. $post_parent = $parent; 
  95. $post_status = $post_status ? $post_status: 'publish'; 
  96. $suffix = ''; 
  97. $post_title = $post->post_title; 
  98. } else { 
  99. $post_parent = $post->post_parent; 
  100. $post_status = $post_status ? $post_status: 'draft'; 
  101. $suffix = ' ' . __( '(Copy)', 'woocommerce' ); 
  102. $post_title = $post->post_title . $suffix; 
  103.  
  104. // Insert the new template in the post table 
  105. $wpdb->insert( 
  106. $wpdb->posts,  
  107. array( 
  108. 'post_author' => $new_post_author->ID,  
  109. 'post_date' => $new_post_date,  
  110. 'post_date_gmt' => $new_post_date_gmt,  
  111. 'post_content' => $post->post_content,  
  112. 'post_content_filtered' => $post->post_content_filtered,  
  113. 'post_title' => $post_title,  
  114. 'post_excerpt' => $post->post_excerpt,  
  115. 'post_status' => $post_status,  
  116. 'post_type' => $post->post_type,  
  117. 'comment_status' => $post->comment_status,  
  118. 'ping_status' => $post->ping_status,  
  119. 'post_password' => $post->post_password,  
  120. 'to_ping' => $post->to_ping,  
  121. 'pinged' => $post->pinged,  
  122. 'post_modified' => $new_post_date,  
  123. 'post_modified_gmt' => $new_post_date_gmt,  
  124. 'post_parent' => $post_parent,  
  125. 'menu_order' => $post->menu_order,  
  126. 'post_mime_type' => $post->post_mime_type 
  127. ); 
  128.  
  129. $new_post_id = $wpdb->insert_id; 
  130.  
  131. // Set title for variations 
  132. if ( 'product_variation' === $post->post_type ) { 
  133. $post_title = sprintf( __( 'Variation #%s of %s', 'woocommerce' ), absint( $new_post_id ), esc_html( get_the_title( $post_parent ) ) ); 
  134. $wpdb->update( 
  135. $wpdb->posts,  
  136. array( 
  137. 'post_title' => $post_title,  
  138. ),  
  139. array( 
  140. 'ID' => $new_post_id 
  141. ); 
  142.  
  143. // Set name and GUID 
  144. if ( ! in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) { 
  145. $wpdb->update( 
  146. $wpdb->posts,  
  147. array( 
  148. 'post_name' => wp_unique_post_slug( sanitize_title( $post_title, $new_post_id ), $new_post_id, $post_status, $post->post_type, $post_parent ),  
  149. 'guid' => get_permalink( $new_post_id ),  
  150. ),  
  151. array( 
  152. 'ID' => $new_post_id 
  153. ); 
  154.  
  155. // Copy the taxonomies 
  156. $this->duplicate_post_taxonomies( $post->ID, $new_post_id, $post->post_type ); 
  157.  
  158. // Copy the meta information 
  159. $this->duplicate_post_meta( $post->ID, $new_post_id ); 
  160.  
  161. // Copy the children (variations) 
  162. $exclude = apply_filters( 'woocommerce_duplicate_product_exclude_children', false ); 
  163.  
  164. if ( ! $exclude && ( $children_products = get_children( 'post_parent=' . $post->ID . '&post_type=product_variation' ) ) ) { 
  165. foreach ( $children_products as $child ) { 
  166. $this->duplicate_product( $this->get_product_to_duplicate( $child->ID ), $new_post_id, $child->post_status ); 
  167.  
  168. // Clear cache 
  169. clean_post_cache( $new_post_id ); 
  170.  
  171. return $new_post_id; 
  172.  
  173. /** 
  174. * Get a product from the database to duplicate. 
  175. * @param mixed $id 
  176. * @return WP_Post|bool 
  177. * @todo Returning false? Need to check for it in... 
  178. * @see duplicate_product 
  179. */ 
  180. private function get_product_to_duplicate( $id ) { 
  181. global $wpdb; 
  182.  
  183. $id = absint( $id ); 
  184.  
  185. if ( ! $id ) { 
  186. return false; 
  187.  
  188. $post = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID=$id" ); 
  189.  
  190. if ( isset( $post->post_type ) && 'revision' === $post->post_type ) { 
  191. $id = $post->post_parent; 
  192. $post = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE ID=$id" ); 
  193.  
  194. return $post[0]; 
  195.  
  196. /** 
  197. * Copy the taxonomies of a post to another post. 
  198. * @param mixed $id 
  199. * @param mixed $new_id 
  200. * @param mixed $post_type 
  201. */ 
  202. private function duplicate_post_taxonomies( $id, $new_id, $post_type ) { 
  203. $exclude = array_filter( apply_filters( 'woocommerce_duplicate_product_exclude_taxonomies', array() ) ); 
  204. $taxonomies = array_diff( get_object_taxonomies( $post_type ), $exclude ); 
  205.  
  206. foreach ( $taxonomies as $taxonomy ) { 
  207. $post_terms = wp_get_object_terms( $id, $taxonomy ); 
  208. $post_terms_count = sizeof( $post_terms ); 
  209.  
  210. for ( $i = 0; $i < $post_terms_count; $i++ ) { 
  211. wp_set_object_terms( $new_id, $post_terms[ $i ]->slug, $taxonomy, true ); 
  212.  
  213. /** 
  214. * Copy the meta information of a post to another post. 
  215. * @param mixed $id 
  216. * @param mixed $new_id 
  217. */ 
  218. private function duplicate_post_meta( $id, $new_id ) { 
  219. global $wpdb; 
  220.  
  221. $sql = $wpdb->prepare( "SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id = %d", absint( $id ) ); 
  222. $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' ) ) ) ); 
  223.  
  224. if ( sizeof( $exclude ) ) { 
  225. $sql .= " AND meta_key NOT IN ( '" . implode( "', '", $exclude ) . "' )"; 
  226.  
  227. $post_meta = $wpdb->get_results( $sql ); 
  228.  
  229. if ( sizeof( $post_meta ) ) { 
  230. $sql_query_sel = array(); 
  231. $sql_query = "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) "; 
  232.  
  233. foreach ( $post_meta as $post_meta_row ) { 
  234. $sql_query_sel[] = $wpdb->prepare( "SELECT %d, %s, %s", $new_id, $post_meta_row->meta_key, $post_meta_row->meta_value ); 
  235.  
  236. $sql_query .= implode( " UNION ALL ", $sql_query_sel ); 
  237. $wpdb->query( $sql_query );