/includes/admin/class-wc-admin-duplicate-product.php

  1. <?php 
  2. if ( ! defined( 'ABSPATH' ) ) { 
  3. exit; 
  4.  
  5. /** 
  6. * Duplicate product functionality 
  7. * 
  8. * @author WooCommerce 
  9. * @category Admin 
  10. * @package WooCommerce/Admin 
  11. * @version 3.0.0 
  12. */ 
  13.  
  14. if ( ! class_exists( 'WC_Admin_Duplicate_Product', false ) ) : 
  15.  
  16. /** 
  17. * WC_Admin_Duplicate_Product Class. 
  18. */ 
  19. class WC_Admin_Duplicate_Product { 
  20.  
  21. /** 
  22. * Constructor. 
  23. */ 
  24. public function __construct() { 
  25. add_action( 'admin_action_duplicate_product', array( $this, 'duplicate_product_action' ) ); 
  26. add_filter( 'post_row_actions', array( $this, 'dupe_link' ), 10, 2 ); 
  27. add_action( 'post_submitbox_start', array( $this, 'dupe_button' ) ); 
  28.  
  29. /** 
  30. * Show the "Duplicate" link in admin products list. 
  31. * @param array $actions 
  32. * @param WP_Post $post Post object 
  33. * @return array 
  34. */ 
  35. public function dupe_link( $actions, $post ) { 
  36. if ( ! current_user_can( apply_filters( 'woocommerce_duplicate_product_capability', 'manage_woocommerce' ) ) ) { 
  37. return $actions; 
  38.  
  39. if ( 'product' !== $post->post_type ) { 
  40. return $actions; 
  41.  
  42. $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' ) 
  43. . '" rel="permalink">' . __( 'Duplicate', 'woocommerce' ) . '</a>'; 
  44.  
  45. return $actions; 
  46.  
  47. /** 
  48. * Show the dupe product link in admin. 
  49. */ 
  50. public function dupe_button() { 
  51. global $post; 
  52.  
  53. if ( ! current_user_can( apply_filters( 'woocommerce_duplicate_product_capability', 'manage_woocommerce' ) ) ) { 
  54. return; 
  55.  
  56. if ( ! is_object( $post ) ) { 
  57. return; 
  58.  
  59. if ( 'product' !== $post->post_type ) { 
  60. return; 
  61.  
  62. if ( isset( $_GET['post'] ) ) { 
  63. $notify_url = wp_nonce_url( admin_url( "edit.php?post_type=product&action=duplicate_product&post=" . absint( $_GET['post'] ) ), 'woocommerce-duplicate-product_' . $_GET['post'] ); 
  64. ?> 
  65. <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> 
  66. <?php 
  67.  
  68. /** 
  69. * Duplicate a product action. 
  70. */ 
  71. public function duplicate_product_action() { 
  72. if ( empty( $_REQUEST['post'] ) ) { 
  73. wp_die( __( 'No product to duplicate has been supplied!', 'woocommerce' ) ); 
  74.  
  75. $product_id = isset( $_REQUEST['post'] ) ? absint( $_REQUEST['post'] ) : ''; 
  76.  
  77. check_admin_referer( 'woocommerce-duplicate-product_' . $product_id ); 
  78.  
  79. $product = wc_get_product( $product_id ); 
  80.  
  81. if ( false === $product ) { 
  82. /** translators: %s: product id */ 
  83. wp_die( sprintf( __( 'Product creation failed, could not find original product: %s', 'woocommerce' ), $product_id ) ); 
  84.  
  85. $duplicate = $this->product_duplicate( $product ); 
  86.  
  87. // Hook rename to match other woocommerce_product_* hooks, and to move away from depending on a response from the wp_posts table. 
  88. do_action( 'woocommerce_product_duplicate', $duplicate, $product ); 
  89. wc_do_deprecated_action( 'woocommerce_duplicate_product', array( $duplicate->get_id(), $this->get_product_to_duplicate( $product_id ) ), '3.0', 'Use woocommerce_product_duplicate action instead.' ); 
  90.  
  91. // Redirect to the edit screen for the new draft page 
  92. wp_redirect( admin_url( 'post.php?action=edit&post=' . $duplicate->get_id() ) ); 
  93. exit; 
  94.  
  95. /** 
  96. * Function to create the duplicate of the product. 
  97. * 
  98. * @param WC_Product $product 
  99. * @return WC_Product 
  100. */ 
  101. public function product_duplicate( $product ) { 
  102. // Filter to allow us to unset/remove data we don't want to copy to the duplicate. @since 2.6 
  103. $meta_to_exclude = array_filter( apply_filters( 'woocommerce_duplicate_product_exclude_meta', array() ) ); 
  104.  
  105. $duplicate = clone $product; 
  106. $duplicate->set_id( 0 ); 
  107. $duplicate->set_name( sprintf( __( '%s (Copy)', 'woocommerce' ), $duplicate->get_name() ) ); 
  108. $duplicate->set_total_sales( 0 ); 
  109. if ( '' !== $product->get_sku( 'edit' ) ) { 
  110. $duplicate->set_sku( wc_product_generate_unique_sku( 0, $product->get_sku( 'edit' ) ) ); 
  111. $duplicate->set_status( 'draft' ); 
  112. $duplicate->set_date_created( null ); 
  113. $duplicate->set_slug( '' ); 
  114. $duplicate->set_rating_counts( 0 ); 
  115. $duplicate->set_average_rating( 0 ); 
  116. $duplicate->set_review_count( 0 ); 
  117.  
  118. foreach ( $meta_to_exclude as $meta_key ) { 
  119. $duplicate->delete_meta_data( $meta_key ); 
  120.  
  121. // This action can be used to modify the object further before it is created - it will be passed by reference. @since 3.0 
  122. do_action( 'woocommerce_product_duplicate_before_save', $duplicate, $product ); 
  123.  
  124. // Save parent product. 
  125. $duplicate->save(); 
  126.  
  127. // Duplicate children of a variable product. 
  128. if ( ! apply_filters( 'woocommerce_duplicate_product_exclude_children', false ) && $product->is_type( 'variable' ) ) { 
  129. foreach ( $product->get_children() as $child_id ) { 
  130. $child = wc_get_product( $child_id ); 
  131. $child_duplicate = clone $child; 
  132. $child_duplicate->set_parent_id( $duplicate->get_id() ); 
  133. $child_duplicate->set_id( 0 ); 
  134.  
  135. if ( '' !== $child->get_sku( 'edit' ) ) { 
  136. $child_duplicate->set_sku( wc_product_generate_unique_sku( 0, $child->get_sku( 'edit' ) ) ); 
  137.  
  138. foreach ( $meta_to_exclude as $meta_key ) { 
  139. $child_duplicate->delete_meta_data( $meta_key ); 
  140.  
  141. // This action can be used to modify the object further before it is created - it will be passed by reference. @since 3.0 
  142. do_action( 'woocommerce_product_duplicate_before_save', $child_duplicate, $child ); 
  143.  
  144. $child_duplicate->save(); 
  145.  
  146. return $duplicate; 
  147.  
  148. /** 
  149. * Get a product from the database to duplicate. 
  150. * 
  151. * @deprecated 3.0.0 
  152. * @param mixed $id 
  153. * @return WP_Post|bool 
  154. * @see duplicate_product 
  155. */ 
  156. private function get_product_to_duplicate( $id ) { 
  157. global $wpdb; 
  158.  
  159. $id = absint( $id ); 
  160.  
  161. if ( ! $id ) { 
  162. return false; 
  163.  
  164. $post = $wpdb->get_row( $wpdb->prepare( "SELECT {$wpdb->posts}.* FROM {$wpdb->posts} WHERE ID = %d", $id ) ); 
  165.  
  166. if ( isset( $post->post_type ) && 'revision' === $post->post_type ) { 
  167. $id = $post->post_parent; 
  168. $post = $wpdb->get_row( $wpdb->prepare( "SELECT {$wpdb->posts}.* FROM {$wpdb->posts} WHERE ID = %d", $id ) ); 
  169.  
  170. return $post; 
  171.  
  172. endif; 
  173.  
  174. return new WC_Admin_Duplicate_Product(); 
.