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