Product Import Export for WooCommerce - Version 1.0.0

Version Description

  • Import /Export Woocommerce Products.

=

Download this release

Release Info

Developer hikeforce
Plugin Icon 128x128 Product Import Export for WooCommerce
Version 1.0.0
Comparing to
See all releases

Version 1.0.0

images/wf-ajax-loader.gif ADDED
Binary file
images/wf-failed.png ADDED
Binary file
images/wf-import.png ADDED
Binary file
images/wf-notice.png ADDED
Binary file
images/wf-success.png ADDED
Binary file
includes/class-wf-prodimpexpcsv-admin-screen.php ADDED
@@ -0,0 +1,84 @@
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ class WF_ProdImpExpCsv_Admin_Screen {
7
+
8
+ /**
9
+ * Constructor
10
+ */
11
+ public function __construct() {
12
+ add_action( 'admin_menu', array( $this, 'admin_menu' ) );
13
+ add_action( 'admin_print_styles', array( $this, 'admin_scripts' ) );
14
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
15
+ }
16
+
17
+ /**
18
+ * Notices in admin
19
+ */
20
+ public function admin_notices() {
21
+ if ( ! function_exists( 'mb_detect_encoding' ) ) {
22
+ echo '<div class="error"><p>' . __( 'Product CSV Import Export requires the function <code>mb_detect_encoding</code> to import and export CSV files. Please ask your hosting provider to enable this function.', 'wf_csv_import_export' ) . '</p></div>';
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Admin Menu
28
+ */
29
+ public function admin_menu() {
30
+ $page = add_submenu_page( 'woocommerce', __( 'Product Im-Ex', 'wf_csv_import_export' ), __( 'Product Im-Ex', 'wf_csv_import_export' ), apply_filters( 'woocommerce_csv_product_role', 'manage_woocommerce' ), 'wf_woocommerce_csv_im_ex', array( $this, 'output' ) );
31
+ }
32
+
33
+ /**
34
+ * Admin Scripts
35
+ */
36
+ public function admin_scripts() {
37
+ wp_enqueue_script( 'chosen' );
38
+ wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css' );
39
+ wp_enqueue_style( 'woocommerce-product-csv-importer', plugins_url( basename( plugin_dir_path( WF_ProdImpExpCsv_FILE ) ) . '/styles/wf-style.css', basename( __FILE__ ) ), '', '1.0.0', 'screen' );
40
+ }
41
+
42
+ /**
43
+ * Admin Screen output
44
+ */
45
+ public function output() {
46
+ //$tab = ! empty( $_GET['tab'] ) && $_GET['tab'] == 'export' ? 'export' : 'import';
47
+ $tab = 'import';
48
+ if( ! empty( $_GET['tab'] ) ) {
49
+ if( $_GET['tab'] == 'export' ) {
50
+ $tab = 'export';
51
+ }
52
+ else if ( $_GET['tab'] == 'settings' ) {
53
+ $tab = 'settings';
54
+ }
55
+ }
56
+ include( 'views/html-wf-admin-screen.php' );
57
+ }
58
+
59
+ /**
60
+ * Admin page for importing
61
+ */
62
+ public function admin_import_page() {
63
+ //include( 'views/html-wf-getting-started.php' );
64
+ include( 'views/import/html-wf-import-products.php' );
65
+ $post_columns = include( 'exporter/data/data-wf-post-columns.php' );
66
+ include( 'views/export/html-wf-export-products.php' );
67
+ }
68
+
69
+ /**
70
+ * Admin Page for exporting
71
+ */
72
+ public function admin_export_page() {
73
+ $post_columns = include( 'exporter/data/data-wf-post-columns.php' );
74
+ include( 'views/export/html-wf-export-products.php' );
75
+ }
76
+
77
+ /**
78
+ * Admin Page for settings
79
+ */
80
+ public function admin_settings_page() {
81
+ }
82
+ }
83
+
84
+ new WF_ProdImpExpCsv_Admin_Screen();
includes/class-wf-prodimpexpcsv-ajax-handler.php ADDED
@@ -0,0 +1,69 @@
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ class WF_ProdImpExpCsv_AJAX_Handler {
7
+
8
+ /**
9
+ * Constructor
10
+ */
11
+ public function __construct() {
12
+ add_action( 'wp_ajax_woocommerce_csv_import_request', array( $this, 'csv_import_request' ) );
13
+ //add_action( 'wp_ajax_woocommerce_csv_import_regenerate_thumbnail', array( $this, 'regenerate_thumbnail' ) );
14
+ }
15
+
16
+ /**
17
+ * Ajax event for importing a CSV
18
+ */
19
+ public function csv_import_request() {
20
+ define( 'WP_LOAD_IMPORTERS', true );
21
+ WF_ProdImpExpCsv_Importer::product_importer();
22
+ }
23
+
24
+ /**
25
+ * From regenerate thumbnails plugin
26
+ */
27
+ public function regenerate_thumbnail() {
28
+ @error_reporting( 0 ); // Don't break the JSON result
29
+
30
+ header( 'Content-type: application/json' );
31
+
32
+ $id = (int) $_REQUEST['id'];
33
+ $image = get_post( $id );
34
+
35
+ if ( ! $image || 'attachment' != $image->post_type || 'image/' != substr( $image->post_mime_type, 0, 6 ) )
36
+ die( json_encode( array( 'error' => sprintf( __( 'Failed resize: %s is an invalid image ID.', 'wf_csv_import_export' ), esc_html( $_REQUEST['id'] ) ) ) ) );
37
+
38
+ if ( ! current_user_can( 'manage_woocommerce' ) )
39
+ $this->die_json_error_msg( $image->ID, __( "Your user account doesn't have permission to resize images", 'wf_csv_import_export' ) );
40
+
41
+ $fullsizepath = get_attached_file( $image->ID );
42
+
43
+ if ( false === $fullsizepath || ! file_exists( $fullsizepath ) )
44
+ $this->die_json_error_msg( $image->ID, sprintf( __( 'The originally uploaded image file cannot be found at %s', 'wf_csv_import_export' ), '<code>' . esc_html( $fullsizepath ) . '</code>' ) );
45
+
46
+ @set_time_limit( 900 ); // 5 minutes per image should be PLENTY
47
+
48
+ $metadata = wp_generate_attachment_metadata( $image->ID, $fullsizepath );
49
+
50
+ if ( is_wp_error( $metadata ) )
51
+ $this->die_json_error_msg( $image->ID, $metadata->get_error_message() );
52
+ if ( empty( $metadata ) )
53
+ $this->die_json_error_msg( $image->ID, __( 'Unknown failure reason.', 'wf_csv_import_export' ) );
54
+
55
+ // If this fails, then it just means that nothing was changed (old value == new value)
56
+ wp_update_attachment_metadata( $image->ID, $metadata );
57
+
58
+ die( json_encode( array( 'success' => sprintf( __( '&quot;%1$s&quot; (ID %2$s) was successfully resized in %3$s seconds.', 'wf_csv_import_export' ), esc_html( get_the_title( $image->ID ) ), $image->ID, timer_stop() ) ) ) );
59
+ }
60
+
61
+ /**
62
+ * Die with a JSON formatted error message
63
+ */
64
+ public function die_json_error_msg( $id, $message ) {
65
+ die( json_encode( array( 'error' => sprintf( __( '&quot;%1$s&quot; (ID %2$s) failed to resize. The error message was: %3$s', 'regenerate-thumbnails' ), esc_html( get_the_title( $id ) ), $id, $message ) ) ) );
66
+ }
67
+ }
68
+
69
+ new WF_ProdImpExpCsv_AJAX_Handler();
includes/class-wf-prodimpexpcsv-system-status-tools.php ADDED
@@ -0,0 +1,103 @@
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ class WF_ProdImpExpCsv_System_Status_Tools {
7
+
8
+ /**
9
+ * Constructor
10
+ */
11
+ public function __construct() {
12
+ add_filter( 'woocommerce_debug_tools', array( $this, 'tools' ) );
13
+ }
14
+
15
+ /**
16
+ * Tools we add to WC
17
+ * @param array $tools
18
+ * @return array
19
+ */
20
+ public function tools( $tools ) {
21
+ $tools['delete_products'] = array(
22
+ 'name' => __( 'Delete Products','wf_csv_import_export'),
23
+ 'button' => __( 'Delete ALL products','wf_csv_import_export' ),
24
+ 'desc' => __( 'This tool will delete all products allowing you to start fresh.', 'wf_csv_import_export' ),
25
+ 'callback' => array( $this, 'delete_products' )
26
+ );
27
+ $tools['delete_variations'] = array(
28
+ 'name' => __( 'Delete Variations','wf_csv_import_export'),
29
+ 'button' => __( 'Delete ALL variations','wf_csv_import_export' ),
30
+ 'desc' => __( 'This tool will delete all variations allowing you to start fresh.', 'wf_csv_import_export' ),
31
+ 'callback' => array( $this, 'delete_variations' )
32
+ );
33
+ $tools['delete_orphaned_variations'] = array(
34
+ 'name' => __( 'Delete Orphans','wf_csv_import_export'),
35
+ 'button' => __( 'Delete orphaned variations','wf_csv_import_export' ),
36
+ 'desc' => __( 'This tool will delete variations which have no parent.', 'wf_csv_import_export' ),
37
+ 'callback' => array( $this, 'delete_orphaned_variations' )
38
+ );
39
+ return $tools;
40
+ }
41
+
42
+ /**
43
+ * Delete products
44
+ */
45
+ public function delete_products() {
46
+ global $wpdb;
47
+
48
+ // Delete products
49
+ $result = absint( $wpdb->delete( $wpdb->posts, array( 'post_type' => 'product' ) ) );
50
+ $result2 = absint( $wpdb->delete( $wpdb->posts, array( 'post_type' => 'product_variation' ) ) );
51
+
52
+ // Delete meta and term relationships with no post
53
+ $wpdb->query( "DELETE pm
54
+ FROM {$wpdb->postmeta} pm
55
+ LEFT JOIN {$wpdb->posts} wp ON wp.ID = pm.post_id
56
+ WHERE wp.ID IS NULL" );
57
+ $wpdb->query( "DELETE tr
58
+ FROM {$wpdb->term_relationships} tr
59
+ LEFT JOIN {$wpdb->posts} wp ON wp.ID = tr.object_id
60
+ WHERE wp.ID IS NULL" );
61
+
62
+ echo '<div class="updated"><p>' . sprintf( __( '%d Products Deleted', 'wf_csv_import_export' ), ( $result + $result2 ) ) . '</p></div>';
63
+ }
64
+
65
+ /**
66
+ * Delete variations
67
+ */
68
+ public function delete_variations() {
69
+ global $wpdb;
70
+
71
+ // Delete products
72
+ $result = absint( $wpdb->delete( $wpdb->posts, array( 'post_type' => 'product_variation' ) ) );
73
+
74
+ // Delete meta and term relationships with no post
75
+ $wpdb->query( "DELETE pm
76
+ FROM {$wpdb->postmeta} pm
77
+ LEFT JOIN {$wpdb->posts} wp ON wp.ID = pm.post_id
78
+ WHERE wp.ID IS NULL" );
79
+ $wpdb->query( "DELETE tr
80
+ FROM {$wpdb->term_relationships} tr
81
+ LEFT JOIN {$wpdb->posts} wp ON wp.ID = tr.object_id
82
+ WHERE wp.ID IS NULL" );
83
+
84
+ echo '<div class="updated"><p>' . sprintf( __( '%d Variations Deleted', 'wf_csv_import_export' ), $result ) . '</p></div>';
85
+ }
86
+
87
+ /**
88
+ * Delete orphans
89
+ */
90
+ public function delete_orphaned_variations() {
91
+ global $wpdb;
92
+
93
+ // Delete meta and term relationships with no post
94
+ $result = absint( $wpdb->query( "DELETE products
95
+ FROM {$wpdb->posts} products
96
+ LEFT JOIN {$wpdb->posts} wp ON wp.ID = products.post_parent
97
+ WHERE wp.ID IS NULL AND products.post_type = 'product_variation';" ) );
98
+
99
+ echo '<div class="updated"><p>' . sprintf( __( '%d Variations Deleted', 'wf_csv_import_export' ), $result ) . '</p></div>';
100
+ }
101
+ }
102
+
103
+ new WF_ProdImpExpCsv_System_Status_Tools();
includes/exporter/class-wf-prodimpexpcsv-exporter.php ADDED
@@ -0,0 +1,530 @@
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ class WF_ProdImpExpCsv_Exporter {
7
+
8
+ /**
9
+ * Product Exporter Tool
10
+ */
11
+ public static function do_export( $post_type = 'product' ) {
12
+ global $wpdb;
13
+
14
+ $export_limit = ! empty( $_POST['limit'] ) ? intval( $_POST['limit'] ) : 999999999;
15
+ $export_count = 0;
16
+ $limit = 100;
17
+ $current_offset = ! empty( $_POST['offset'] ) ? intval( $_POST['offset'] ) : 0;
18
+ $csv_columns = include( 'data/data-wf-post-columns.php' );
19
+ $user_columns_name = ! empty( $_POST['columns_name'] ) ? $_POST['columns_name'] : $csv_columns;
20
+ $product_taxonomies = get_object_taxonomies( 'product', 'name' );
21
+ $export_columns = ! empty( $_POST['columns'] ) ? $_POST['columns'] : '';
22
+ $include_hidden_meta = ! empty( $_POST['include_hidden_meta'] ) ? true : false;
23
+ $product_limit = ! empty( $_POST['product_limit'] ) ? sanitize_text_field( $_POST['product_limit'] ) : '';
24
+ $exclude_hidden_meta_columns = include( 'data/data-wf-hidden-meta-columns.php' );
25
+
26
+ if ( $limit > $export_limit )
27
+ $limit = $export_limit;
28
+
29
+ $wpdb->hide_errors();
30
+ @set_time_limit(0);
31
+ if ( function_exists( 'apache_setenv' ) )
32
+ @apache_setenv( 'no-gzip', 1 );
33
+ @ini_set('zlib.output_compression', 0);
34
+ @ob_clean();
35
+
36
+
37
+ header( 'Content-Type: text/csv; charset=UTF-8' );
38
+ header( 'Content-Disposition: attachment; filename=woocommerce-product-export.csv' );
39
+ header( 'Pragma: no-cache' );
40
+ header( 'Expires: 0' );
41
+
42
+ $fp = fopen('php://output', 'w');
43
+
44
+
45
+ // Headers
46
+ $all_meta_keys = self::get_all_metakeys( 'product' );
47
+ $found_attributes = self::get_all_product_attributes( 'product' );
48
+
49
+ // Loop products and load meta data
50
+ $found_product_meta = array();
51
+ // Some of the values may not be usable (e.g. arrays of arrays) but the worse
52
+ // that can happen is we get an empty column.
53
+ foreach ( $all_meta_keys as $meta ) {
54
+ if ( ! $meta ) continue;
55
+ if ( ! $include_hidden_meta && ! in_array( $meta, array_keys( $csv_columns ) ) && substr( (string)$meta, 0, 1 ) == '_' )
56
+ continue;
57
+ if ( $include_hidden_meta && ( in_array( $meta, $exclude_hidden_meta_columns ) || in_array( $meta, array_keys( $csv_columns ) ) ) )
58
+ continue;
59
+ $found_product_meta[] = $meta;
60
+ }
61
+
62
+ $found_product_meta = array_diff( $found_product_meta, array_keys( $csv_columns ) );
63
+
64
+ // Variable to hold the CSV data we're exporting
65
+ $row = array();
66
+
67
+ // Export header rows
68
+ foreach ( $csv_columns as $column => $value ) {
69
+
70
+ $temp_head = esc_attr( $user_columns_name[$column] );
71
+ if (strpos($temp_head, 'yoast') === false) {
72
+ $temp_head = ltrim($temp_head, '_');
73
+ }
74
+ if ( ! $export_columns || in_array( $column, $export_columns ) ) $row[] = $temp_head;
75
+ }
76
+
77
+ // Handle special fields like taxonomies
78
+ if ( ! $export_columns || in_array( 'images', $export_columns ) ) {
79
+ $row[] = 'images';
80
+ }
81
+
82
+ if ( ! $export_columns || in_array( 'file_paths', $export_columns ) ) {
83
+ if ( function_exists( 'wc_get_filename_from_url' ) ) {
84
+ $row[] = 'downloadable_files';
85
+ } else {
86
+ $row[] = 'file_paths';
87
+ }
88
+ }
89
+
90
+ if ( ! $export_columns || in_array( 'taxonomies', $export_columns ) ) {
91
+ foreach ( $product_taxonomies as $taxonomy ) {
92
+ if ( strstr( $taxonomy->name, 'pa_' ) ) continue; // Skip attributes
93
+
94
+ $row[] = 'tax:' . self::format_data( $taxonomy->name );
95
+ }
96
+ }
97
+
98
+ if ( ! $export_columns || in_array( 'meta', $export_columns ) ) {
99
+ foreach ( $found_product_meta as $product_meta ) {
100
+ $row[] = 'meta:' . self::format_data( $product_meta );
101
+ }
102
+ }
103
+
104
+ if ( ! $export_columns || in_array( 'attributes', $export_columns ) ) {
105
+ foreach ( $found_attributes as $attribute ) {
106
+ $row[] = 'attribute:' . self::format_data( $attribute );
107
+ $row[] = 'attribute_data:' . self::format_data( $attribute );
108
+ $row[] = 'attribute_default:' . self::format_data( $attribute );
109
+ }
110
+ }
111
+
112
+
113
+
114
+ // WF: Adding product permalink.
115
+ if ( ! $export_columns || in_array( 'product_page_url', $export_columns ) ) {
116
+ $row[] = 'Product Page URL';
117
+ }
118
+
119
+ $row = array_map( 'WF_ProdImpExpCsv_Exporter::wrap_column', $row );
120
+ fwrite( $fp, implode( ',', $row ) . "\n" );
121
+ unset( $row );
122
+
123
+ while ( $export_count < $export_limit ) {
124
+
125
+ $product_args = apply_filters( 'woocommerce_csv_product_export_args', array(
126
+ 'numberposts' => $limit,
127
+ 'post_status' => array( 'publish', 'pending', 'private', 'draft' ),
128
+ 'post_type' => array('product'),
129
+ 'orderby' => 'ID',
130
+ 'order' => 'ASC',
131
+ 'offset' => $current_offset
132
+ ) );
133
+
134
+
135
+ $product_args['orderby'] = 'post_parent';
136
+
137
+ if ( $product_limit ) {
138
+ $parent_ids = array_map( 'intval', explode( ',', $product_limit ) );
139
+ $child_ids = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_parent IN (" . implode( ',', $parent_ids ) . ");" );
140
+ $product_args['post__in'] = $child_ids;
141
+ }
142
+
143
+ $products = get_posts( $product_args );
144
+ if ( ! $products || is_wp_error( $products ) )
145
+ break;
146
+
147
+ // Loop products
148
+ foreach ( $products as $product ) {
149
+ if($product->post_parent == 0) $product->post_parent = '';
150
+ $row = array();
151
+
152
+ // Pre-process data
153
+ $meta_data = get_post_custom( $product->ID );
154
+
155
+ $product->meta = new stdClass;
156
+ $product->attributes = new stdClass;
157
+
158
+ // Meta data
159
+ foreach ( $meta_data as $meta => $value ) {
160
+ if ( ! $meta ) {
161
+ continue;
162
+ }
163
+ if ( ! $include_hidden_meta && ! in_array( $meta, array_keys( $csv_columns ) ) && substr( $meta, 0, 1 ) == '_' ) {
164
+ continue;
165
+ }
166
+ if ( $include_hidden_meta && in_array( $meta, $exclude_hidden_meta_columns ) ) {
167
+ continue;
168
+ }
169
+
170
+ $meta_value = maybe_unserialize( maybe_unserialize( $value[0] ) );
171
+
172
+ if ( is_array( $meta_value ) ) {
173
+ $meta_value = json_encode( $meta_value );
174
+ }
175
+
176
+ $product->meta->$meta = self::format_export_meta( $meta_value, $meta );
177
+ }
178
+
179
+ // Product attributes
180
+ if ( isset( $meta_data['_product_attributes'][0] ) ) {
181
+
182
+ $attributes = maybe_unserialize( maybe_unserialize( $meta_data['_product_attributes'][0] ) );
183
+
184
+ if ( ! empty( $attributes ) && is_array( $attributes ) ) {
185
+ foreach ( $attributes as $key => $attribute ) {
186
+ if ( ! $key ) {
187
+ continue;
188
+ }
189
+
190
+ if ( $attribute['is_taxonomy'] == 1 ) {
191
+ $terms = wp_get_post_terms( $product->ID, $key, array("fields" => "names") );
192
+ if ( ! is_wp_error( $terms ) ) {
193
+ $attribute_value = implode( '|', $terms );
194
+ } else {
195
+ $attribute_value = '';
196
+ }
197
+ } else {
198
+ if ( empty( $attribute['name'] ) ) {
199
+ continue;
200
+ }
201
+ $key = $attribute['name'];
202
+ $attribute_value = $attribute['value'];
203
+ }
204
+
205
+ if ( ! isset( $attribute['position'] ) ) {
206
+ $attribute['position'] = 0;
207
+ }
208
+ if ( ! isset( $attribute['is_visible'] ) ) {
209
+ $attribute['is_visible'] = 0;
210
+ }
211
+ if ( ! isset( $attribute['is_variation'] ) ) {
212
+ $attribute['is_variation'] = 0;
213
+ }
214
+
215
+ $attribute_data = $attribute['position'] . '|' . $attribute['is_visible'] . '|' . $attribute['is_variation'];
216
+ $_default_attributes = isset( $meta_data['_default_attributes'][0] ) ? maybe_unserialize( maybe_unserialize( $meta_data['_default_attributes'][0] ) ) : '';
217
+
218
+ if ( is_array( $_default_attributes ) ) {
219
+ $_default_attribute = isset( $_default_attributes[ $key ] ) ? $_default_attributes[ $key ] : '';
220
+ } else {
221
+ $_default_attribute = '';
222
+ }
223
+
224
+ $product->attributes->$key = array(
225
+ 'value' => $attribute_value,
226
+ 'data' => $attribute_data,
227
+ 'default' => $_default_attribute
228
+ );
229
+ }
230
+ }
231
+ }
232
+
233
+ // GPF
234
+ if ( isset( $meta_data['_woocommerce_gpf_data'][0] ) ) {
235
+ $product->gpf_data = $meta_data['_woocommerce_gpf_data'][0];
236
+ }
237
+
238
+ // Get column values
239
+ foreach ( $csv_columns as $column => $value ) {
240
+ if ( ! $export_columns || in_array( $column, $export_columns ) ) {
241
+
242
+ if ($column == '_regular_price' && empty( $product->meta->$column ) ) {
243
+ $column = '_price';
244
+ }
245
+
246
+ if ( isset( $product->meta->$column ) ) {
247
+ $row[] = self::format_data( $product->meta->$column );
248
+ } elseif ( isset( $product->$column ) && ! is_array( $product->$column ) ) {
249
+ if ( $column === 'post_title' ) {
250
+ $row[] = sanitize_text_field( $product->$column );
251
+ } else {
252
+ $row[] = self::format_data( $product->$column );
253
+ }
254
+ } else {
255
+ $row[] = '';
256
+ }
257
+ }
258
+ }
259
+
260
+ // Export images/gallery
261
+ if ( ! $export_columns || in_array( 'images', $export_columns ) ) {
262
+
263
+ $image_file_names = array();
264
+
265
+ // Featured image
266
+ if ( ( $featured_image_id = get_post_thumbnail_id( $product->ID ) ) && ( $image = wp_get_attachment_image_src( $featured_image_id, 'full' ) ) ) {
267
+ $image_file_names[] = current( $image );
268
+ }
269
+
270
+ // Images
271
+ $images = isset( $meta_data['_product_image_gallery'][0] ) ? explode( ',', maybe_unserialize( maybe_unserialize( $meta_data['_product_image_gallery'][0] ) ) ) : false;
272
+ $results = array();
273
+
274
+ if ( $images ) {
275
+ foreach ( $images as $image_id ) {
276
+ if ( $featured_image_id == $image_id ) {
277
+ continue;
278
+ }
279
+ $image = wp_get_attachment_image_src( $image_id, 'full' );
280
+ if ( $image ) {
281
+ $image_file_names[] = current( $image );
282
+ }
283
+ }
284
+ }
285
+
286
+ $row[] = implode( ' | ', $image_file_names );
287
+
288
+ }
289
+
290
+ // Downloadable files
291
+ if ( ! $export_columns || in_array( 'file_paths', $export_columns ) ) {
292
+ if ( ! function_exists( 'wc_get_filename_from_url' ) ) {
293
+ $file_paths = maybe_unserialize( maybe_unserialize( $meta_data['_file_paths'][0] ) );
294
+ $file_paths_to_export = array();
295
+
296
+ if ( $file_paths ) {
297
+ foreach ( $file_paths as $file_path ) {
298
+ $file_paths_to_export[] = $file_path;
299
+ }
300
+ }
301
+
302
+ $file_paths_to_export = implode( ' | ', $file_paths_to_export );
303
+ $row[] = self::format_data( $file_paths_to_export );
304
+ } elseif ( isset( $meta_data['_downloadable_files'][0] ) ) {
305
+ $file_paths = maybe_unserialize( maybe_unserialize( $meta_data['_downloadable_files'][0] ) );
306
+ $file_paths_to_export = array();
307
+
308
+ if ( $file_paths ) {
309
+ foreach ( $file_paths as $file_path ) {
310
+ $file_paths_to_export[] = ( ! empty( $file_path['name'] ) ? $file_path['name'] : wc_get_filename_from_url( $file_path['file'] ) ) . '::' . $file_path['file'];
311
+ }
312
+ }
313
+ $file_paths_to_export = implode( ' | ', $file_paths_to_export );
314
+ $row[] = self::format_data( $file_paths_to_export );
315
+ } else {
316
+ $row[] = '';
317
+ }
318
+ }
319
+
320
+ // Export taxonomies
321
+ if ( ! $export_columns || in_array( 'taxonomies', $export_columns ) ) {
322
+ foreach ( $product_taxonomies as $taxonomy ) {
323
+ if ( strstr( $taxonomy->name, 'pa_' ) ) continue; // Skip attributes
324
+
325
+ if ( is_taxonomy_hierarchical( $taxonomy->name ) ) {
326
+ $terms = wp_get_post_terms( $product->ID, $taxonomy->name, array( "fields" => "all" ) );
327
+ $formatted_terms = array();
328
+
329
+ foreach ( $terms as $term ) {
330
+ $ancestors = array_reverse( get_ancestors( $term->term_id, $taxonomy->name ) );
331
+ $formatted_term = array();
332
+
333
+ foreach ( $ancestors as $ancestor )
334
+ $formatted_term[] = get_term( $ancestor, $taxonomy->name )->name;
335
+
336
+ $formatted_term[] = $term->name;
337
+
338
+ $formatted_terms[] = implode( ' > ', $formatted_term );
339
+ }
340
+
341
+ $row[] = self::format_data( implode( '|', $formatted_terms ) );
342
+ } else {
343
+ $terms = wp_get_post_terms( $product->ID, $taxonomy->name, array( "fields" => "names" ) );
344
+
345
+ $row[] = self::format_data( implode( '|', $terms ) );
346
+ }
347
+ }
348
+ }
349
+
350
+ // Export meta data
351
+ if ( ! $export_columns || in_array( 'meta', $export_columns ) ) {
352
+ foreach ( $found_product_meta as $product_meta ) {
353
+ if ( isset( $product->meta->$product_meta ) ) {
354
+ $row[] = self::format_data( $product->meta->$product_meta );
355
+ } else {
356
+ $row[] = '';
357
+ }
358
+ }
359
+ }
360
+
361
+ // Find and export attributes
362
+ if ( ! $export_columns || in_array( 'attributes', $export_columns ) ) {
363
+ foreach ( $found_attributes as $attribute ) {
364
+ if ( isset( $product->attributes ) && isset( $product->attributes->$attribute ) ) {
365
+ $values = $product->attributes->$attribute;
366
+ $row[] = self::format_data( $values['value'] );
367
+ $row[] = self::format_data( $values['data'] );
368
+ $row[] = self::format_data( $values['default'] );
369
+ } else {
370
+ $row[] = '';
371
+ $row[] = '';
372
+ $row[] = '';
373
+ }
374
+ }
375
+ }
376
+
377
+ // Export GPF
378
+ if ( function_exists( 'woocommerce_gpf_install' ) && ( ! $export_columns || in_array( 'gpf', $export_columns ) ) ) {
379
+
380
+ $gpf_data = empty( $product->gpf_data ) ? '' : maybe_unserialize( $product->gpf_data );
381
+
382
+ $row[] = empty( $gpf_data['availability'] ) ? '' : $gpf_data['availability'];
383
+ $row[] = empty( $gpf_data['condition'] ) ? '' : $gpf_data['condition'];
384
+ $row[] = empty( $gpf_data['brand'] ) ? '' : $gpf_data['brand'];
385
+ $row[] = empty( $gpf_data['product_type'] ) ? '' : $gpf_data['product_type'];
386
+ $row[] = empty( $gpf_data['google_product_category'] ) ? '' : $gpf_data['google_product_category'];
387
+ $row[] = empty( $gpf_data['gtin'] ) ? '' : $gpf_data['gtin'];
388
+ $row[] = empty( $gpf_data['mpn'] ) ? '' : $gpf_data['mpn'];
389
+ $row[] = empty( $gpf_data['gender'] ) ? '' : $gpf_data['gender'];
390
+ $row[] = empty( $gpf_data['age_group'] ) ? '' : $gpf_data['age_group'];
391
+ $row[] = empty( $gpf_data['color'] ) ? '' : $gpf_data['color'];
392
+ $row[] = empty( $gpf_data['size'] ) ? '' : $gpf_data['size'];
393
+ $row[] = empty( $gpf_data['adwords_grouping'] ) ? '' : $gpf_data['adwords_grouping'];
394
+ $row[] = empty( $gpf_data['adwords_labels'] ) ? '' : $gpf_data['adwords_labels'];
395
+ }
396
+
397
+ // WF: Adding product permalink.
398
+ if ( ! $export_columns || in_array( 'product_page_url', $export_columns ) ) {
399
+ $product_page_url = '';
400
+ if ( $product->ID ) {
401
+ $product_page_url = get_permalink( $product->ID );
402
+ }
403
+ if ( $product->post_parent ) {
404
+ $product_page_url = get_permalink( $product->post_parent );
405
+ }
406
+
407
+ $row[] = $product_page_url;
408
+ }
409
+
410
+ // Add to csv
411
+ $row = array_map( 'WF_ProdImpExpCsv_Exporter::wrap_column', $row );
412
+ fwrite( $fp, implode( ',', $row ) . "\n" );
413
+ unset( $row );
414
+
415
+ }
416
+ $current_offset += $limit;
417
+ $export_count += $limit;
418
+ unset( $products );
419
+ }
420
+
421
+ fclose( $fp );
422
+ exit;
423
+ }
424
+
425
+ /**
426
+ * Format the data if required
427
+ * @param string $meta_value
428
+ * @param string $meta name of meta key
429
+ * @return string
430
+ */
431
+ public static function format_export_meta( $meta_value, $meta ) {
432
+ switch ( $meta ) {
433
+ case '_sale_price_dates_from' :
434
+ case '_sale_price_dates_to' :
435
+ return $meta_value ? date( 'Y-m-d', $meta_value ) : '';
436
+ break;
437
+ case '_upsell_ids' :
438
+ case '_crosssell_ids' :
439
+ return implode( '|', array_filter( (array) json_decode( $meta_value ) ) );
440
+ break;
441
+ default :
442
+ return $meta_value;
443
+ break;
444
+ }
445
+ }
446
+
447
+ public static function format_data( $data ) {
448
+ if(!is_array($data));
449
+ $data = (string) urldecode( $data );
450
+ $enc = mb_detect_encoding( $data, 'UTF-8, ISO-8859-1', true );
451
+ $data = ( $enc == 'UTF-8' ) ? $data : utf8_encode( $data );
452
+ return $data;
453
+ }
454
+
455
+ /**
456
+ * Wrap a column in quotes for the CSV
457
+ * @param string data to wrap
458
+ * @return string wrapped data
459
+ */
460
+ public static function wrap_column( $data ) {
461
+ return '"' . str_replace( '"', '""', $data ) . '"';
462
+ }
463
+
464
+ /**
465
+ * Get a list of all the meta keys for a post type. This includes all public, private,
466
+ * used, no-longer used etc. They will be sorted once fetched.
467
+ */
468
+ public static function get_all_metakeys( $post_type = 'product' ) {
469
+ global $wpdb;
470
+
471
+ $meta = $wpdb->get_col( $wpdb->prepare(
472
+ "SELECT DISTINCT pm.meta_key
473
+ FROM {$wpdb->postmeta} AS pm
474
+ LEFT JOIN {$wpdb->posts} AS p ON p.ID = pm.post_id
475
+ WHERE p.post_type = %s
476
+ AND p.post_status IN ( 'publish', 'pending', 'private', 'draft' )",
477
+ $post_type
478
+ ) );
479
+
480
+ sort( $meta );
481
+
482
+ return $meta;
483
+ }
484
+
485
+ /**
486
+ * Get a list of all the product attributes for a post type.
487
+ * These require a bit more digging into the values.
488
+ */
489
+ public static function get_all_product_attributes( $post_type = 'product' ) {
490
+ global $wpdb;
491
+
492
+ $results = $wpdb->get_col( $wpdb->prepare(
493
+ "SELECT DISTINCT pm.meta_value
494
+ FROM {$wpdb->postmeta} AS pm
495
+ LEFT JOIN {$wpdb->posts} AS p ON p.ID = pm.post_id
496
+ WHERE p.post_type = %s
497
+ AND p.post_status IN ( 'publish', 'pending', 'private', 'draft' )
498
+ AND pm.meta_key = '_product_attributes'",
499
+ $post_type
500
+ ) );
501
+
502
+ // Go through each result, and look at the attribute keys within them.
503
+ $result = array();
504
+
505
+ if ( ! empty( $results ) ) {
506
+ foreach( $results as $_product_attributes ) {
507
+ $attributes = maybe_unserialize( maybe_unserialize( $_product_attributes ) );
508
+ if ( ! empty( $attributes ) && is_array( $attributes ) ) {
509
+ foreach( $attributes as $key => $attribute ) {
510
+ if ( ! $key ) {
511
+ continue;
512
+ }
513
+ if ( ! strstr( $key, 'pa_' ) ) {
514
+ if ( empty( $attribute['name'] ) ) {
515
+ continue;
516
+ }
517
+ $key = $attribute['name'];
518
+ }
519
+
520
+ $result[ $key ] = $key;
521
+ }
522
+ }
523
+ }
524
+ }
525
+
526
+ sort( $result );
527
+
528
+ return $result;
529
+ }
530
+ }
includes/exporter/data/data-wf-hidden-meta-columns.php ADDED
@@ -0,0 +1,20 @@
1
+ <?php
2
+
3
+ // Exclude columns handled specifically
4
+ return array(
5
+ '_product_attributes',
6
+ '_file_paths',
7
+ '_woocommerce_gpf_data',
8
+ '_price',
9
+ '_default_attributes',
10
+ '_edit_last',
11
+ '_edit_lock',
12
+ '_wp_old_slug',
13
+ '_product_image_gallery',
14
+ '_max_variation_price',
15
+ '_max_variation_regular_price',
16
+ '_max_variation_sale_price',
17
+ '_min_variation_price',
18
+ '_min_variation_regular_price',
19
+ '_min_variation_sale_price',
20
+ );
includes/exporter/data/data-wf-post-columns.php ADDED
@@ -0,0 +1,51 @@
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ return apply_filters('woocommerce_csv_product_post_columns', array(
7
+ 'post_title' => 'post_title',
8
+ 'post_name' => 'post_name',
9
+ 'ID' => 'ID',
10
+ 'post_excerpt' => 'post_excerpt',
11
+ 'post_content' => 'post_content',
12
+ 'post_status' => 'post_status',
13
+ 'menu_order' => 'menu_order',
14
+ 'post_date' => 'post_date',
15
+ 'post_author' => 'post_author',
16
+ 'comment_status' => 'comment_status',
17
+
18
+ // Meta
19
+ '_sku' => 'sku',
20
+ '_downloadable' => 'downloadable',
21
+ '_virtual' => 'virtual',
22
+ '_stock' => 'stock',
23
+ '_regular_price' => 'regular_price',
24
+ '_sale_price' => 'sale_price',
25
+ '_weight' => 'weight',
26
+ '_length' => 'length',
27
+ '_width' => 'width',
28
+ '_height' => 'height',
29
+ '_tax_class' => 'tax_class',
30
+
31
+ '_visibility' => 'visibility',
32
+ '_stock_status' => 'stock_status',
33
+ '_backorders' => 'backorders',
34
+ '_manage_stock' => 'manage_stock',
35
+ '_tax_status' => 'tax_status',
36
+ '_upsell_ids' => 'upsell_ids',
37
+ '_crosssell_ids' => 'crosssell_ids',
38
+ '_featured' => 'featured',
39
+
40
+ '_sale_price_dates_from' => 'sale_price_dates_from',
41
+ '_sale_price_dates_to' => 'sale_price_dates_to',
42
+
43
+ // Downloadable products
44
+ '_download_limit' => 'download_limit',
45
+ '_download_expiry' => 'download_expiry',
46
+
47
+ // Virtual products
48
+ '_product_url' => 'product_url',
49
+ '_button_text' => 'button_text',
50
+
51
+ ) );
includes/importer/class-wf-csv-parser.php ADDED
@@ -0,0 +1,948 @@
1
+ <?php
2
+ /**
3
+ * WooCommerce CSV Importer class for managing parsing of CSV files.
4
+ */
5
+ class WF_CSV_Parser {
6
+
7
+ var $row;
8
+ var $post_type;
9
+ var $reserved_fields; // Fields we map/handle (not custom fields)
10
+ var $post_defaults; // Default post data
11
+ var $postmeta_defaults; // default post meta
12
+ var $postmeta_allowed; // post meta validation
13
+ var $allowed_product_types; // Allowed product types
14
+
15
+ /**
16
+ * Constructor
17
+ */
18
+ public function __construct( $post_type = 'product' ) {
19
+ $this->post_type = $post_type;
20
+ $this->reserved_fields = include( 'data/data-wf-reserved-fields.php' );
21
+ $this->post_defaults = include( 'data/data-wf-post-defaults.php' );
22
+ $this->postmeta_defaults = include( 'data/data-wf-postmeta-defaults.php' );
23
+ $this->postmeta_allowed = include( 'data/data-wf-postmeta-allowed.php' );
24
+
25
+ $simple_term = get_term_by( 'slug', 'simple', 'product_type' );
26
+ $variable_term = get_term_by( 'slug', 'variable', 'product_type' );
27
+ $grouped_term = get_term_by( 'slug', 'grouped', 'product_type' );
28
+ $external_term = get_term_by( 'slug', 'external', 'product_type' );
29
+
30
+ $this->allowed_product_types = array(
31
+ 'simple' => $simple_term->term_id,
32
+ 'variable' => $variable_term->term_id,
33
+ 'grouped' => $grouped_term->term_id,
34
+ 'external' => $external_term->term_id
35
+ );
36
+
37
+ // Subscription product types
38
+ if ( class_exists( 'WC_Subscriptions' ) ) {
39
+ $subscription_term = get_term_by( 'slug', 'subscription', 'product_type' );
40
+ $variable_subscription_term = get_term_by( 'slug', 'variable-subscription', 'product_type' );
41
+
42
+ $this->allowed_product_types['subscription'] = $subscription_term->term_id;
43
+ $this->allowed_product_types['variable-subscription'] = $variable_subscription_term->term_id;
44
+ }
45
+
46
+ // Composite product type
47
+ if ( class_exists( 'WC_Composite_Products' ) ) {
48
+ $composite_term = get_term_by( 'name', 'composite', 'product_type' );
49
+
50
+ if ( $composite_term ) {
51
+ $this->allowed_product_types['composite'] = $composite_term->term_id;
52
+ }
53
+ }
54
+
55
+ // Bundle product type
56
+ if ( class_exists( 'WC_Bundles' ) ) {
57
+ $bundle_term = get_term_by( 'name', 'bundle', 'product_type' );
58
+
59
+ if ( $bundle_term ) {
60
+ $this->allowed_product_types['bundle'] = $bundle_term->term_id;
61
+ }
62
+ }
63
+
64
+ // Booking product types
65
+ if ( class_exists( 'WC_Booking' ) ) {
66
+ $booking_term = get_term_by( 'slug', 'booking', 'product_type' );
67
+
68
+ if ( $booking_term ) {
69
+ $this->allowed_product_types['booking'] = $booking_term->term_id;
70
+ }
71
+ }
72
+
73
+ // Photography product types
74
+ if ( class_exists( 'WC_Photography' ) ) {
75
+ $photography_term = get_term_by( 'slug', 'photography', 'product_type' );
76
+
77
+ if ( $photography_term ) {
78
+ $this->allowed_product_types['photography'] = $photography_term->term_id;
79
+ }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Format data from the csv file
85
+ * @param string $data
86
+ * @param string $enc
87
+ * @return string
88
+ */
89
+ public function format_data_from_csv( $data, $enc ) {
90
+ return ( $enc == 'UTF-8' ) ? $data : utf8_encode( $data );
91
+ }
92
+
93
+ /**
94
+ * Parse the data
95
+ * @param string $file [description]
96
+ * @param string $delimiter [description]
97
+ * @param array $mapping [description]
98
+ * @param integer $start_pos [description]
99
+ * @param integer $end_pos [description]
100
+ * @return array
101
+ */
102
+ public function parse_data( $file, $delimiter, $mapping, $start_pos = 0, $end_pos = null, $eval_field ) {
103
+ // Set locale
104
+ $enc = mb_detect_encoding( $file, 'UTF-8, ISO-8859-1', true );
105
+ if ( $enc )
106
+ setlocale( LC_ALL, 'en_US.' . $enc );
107
+ @ini_set( 'auto_detect_line_endings', true );
108
+
109
+ $parsed_data = array();
110
+ $raw_headers = array();
111
+
112
+ // Put all CSV data into an associative array
113
+ if ( ( $handle = fopen( $file, "r" ) ) !== FALSE ) {
114
+
115
+ $header = fgetcsv( $handle, 0, $delimiter );
116
+ if ( $start_pos != 0 )
117
+ fseek( $handle, $start_pos );
118
+
119
+ while ( ( $postmeta = fgetcsv( $handle, 0, $delimiter ) ) !== FALSE ) {
120
+ $row = array();
121
+
122
+ foreach ( $header as $key => $heading ) {
123
+ // Heading is the lowercase version of the column name
124
+ $s_heading = strtolower( $heading );
125
+
126
+ // Check if this heading is being mapped to a different field
127
+ if ( isset( $mapping[$s_heading] ) ) {
128
+ if ( $mapping[$s_heading] == 'import_as_meta' ) {
129
+
130
+ $s_heading = 'meta:' . $s_heading;
131
+
132
+ } elseif ( $mapping[$s_heading] == 'import_as_images' ) {
133
+
134
+ $s_heading = 'images';
135
+
136
+ } else {
137
+ $s_heading = esc_attr( $mapping[$s_heading] );
138
+ }
139
+ }
140
+ foreach ($mapping as $mkey => $mvalue) {
141
+ if(trim($mvalue) === trim($heading)){
142
+ $s_heading = $mkey;
143
+ }
144
+ }
145
+
146
+ if ( $s_heading == '' )
147
+ continue;
148
+
149
+ // Add the heading to the parsed data
150
+ $row[$s_heading] = ( isset( $postmeta[$key] ) ) ? $this->format_data_from_csv( $postmeta[$key], $enc ) : '';
151
+
152
+ $row[$s_heading] = $this->evaluate_field($row[$s_heading], $eval_field[strtolower( $heading )]);
153
+
154
+ // Raw Headers stores the actual column name in the CSV
155
+ $raw_headers[ $s_heading ] = $heading;
156
+ }
157
+ $parsed_data[] = $row;
158
+
159
+ unset( $postmeta, $row );
160
+
161
+ $position = ftell( $handle );
162
+
163
+ if ( $end_pos && $position >= $end_pos )
164
+ break;
165
+ }
166
+ fclose( $handle );
167
+ }
168
+ return array( $parsed_data, $raw_headers, $position );
169
+ }
170
+
171
+ private function evaluate_field($value, $evaluation_field){
172
+ //echo "value:$value, $evaluation_field </br>";
173
+ $processed_value = $value;
174
+ if(!empty($evaluation_field)){
175
+ $operator = substr($evaluation_field, 0, 1);
176
+ if(in_array($operator, array('=', '+', '-', '*', '/', '&'))){
177
+ $eval_val = substr($evaluation_field, 1);
178
+ //echo "operator:$operator";
179
+ switch($operator){
180
+ case '=':
181
+ $processed_value = $eval_val;
182
+ break;
183
+ case '+':
184
+ $processed_value = $value + $eval_val;
185
+ break;
186
+ case '-':
187
+ $processed_value = $value - $eval_val;
188
+ break;
189
+ case '*':
190
+ $processed_value = $value * $eval_val;
191
+ break;
192
+ case '/':
193
+ $processed_value = $value / $eval_val;
194
+ break;
195
+ case '&':
196
+ if (strpos($eval_val, '[VAL]') !== false) {
197
+ $processed_value = str_replace('[VAL]',$value,$eval_val);
198
+ }
199
+ else{
200
+ $processed_value = $value . $eval_val;
201
+ }
202
+ break;
203
+ }
204
+ }
205
+ }
206
+ return $processed_value;
207
+ }
208
+
209
+ /**
210
+ * Parse product
211
+ * @param array $item
212
+ * @param integer $merge_empty_cells
213
+ * @return array
214
+ */
215
+ public function parse_product( $item, $merge_empty_cells = 0 ) {
216
+ global $WF_CSV_Product_Import, $wpdb;
217
+ $this->row++;
218
+
219
+ $terms_array = $postmeta = $product = array();
220
+ $attributes = $default_attributes = $gpf_data = null;
221
+
222
+ // Merging
223
+ $merging = ( ! empty( $_GET['merge'] ) && $_GET['merge'] ) ? true : false;
224
+ //if($item['post_parent']!== '' && $item['parent_sku'] !== ''){
225
+
226
+ $this->post_defaults['post_type'] = 'product';
227
+
228
+ // Post ID field mapping
229
+ $post_id = ( ! empty( $item['id'] ) ) ? $item['id'] : 0;
230
+ $post_id = ( ! empty( $item['post_id'] ) ) ? $item['post_id'] : $post_id;
231
+ if ( $merging ) {
232
+
233
+ $product['merging'] = true;
234
+
235
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __('> Row %s - preparing for merge.', 'wf_csv_import_export'), $this->row ) );
236
+
237
+ // Required fields
238
+ if ( ! $post_id && empty( $item['sku'] ) ) {
239
+
240
+ $WF_CSV_Product_Import->log->add( 'csv-import', __( '> > Cannot merge without id or sku. Importing instead.', 'wf_csv_import_export') );
241
+
242
+ $merging = false;
243
+ } else {
244
+
245
+ // Check product exists
246
+ if ( ! $post_id ) {
247
+ $post_db_type = $this->post_defaults['post_type'];
248
+ $post_pass_type = '"'.$post_db_type.'"';
249
+ // Check product to merge exists
250
+ $db_query = $wpdb->prepare("
251
+ SELECT $wpdb->posts.ID
252
+ FROM $wpdb->posts
253
+ LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
254
+ WHERE $wpdb->posts.post_type = $post_pass_type
255
+ AND $wpdb->posts.post_status IN ( 'publish', 'private', 'draft', 'pending', 'future' )
256
+ AND $wpdb->postmeta.meta_key = '_sku' AND $wpdb->postmeta.meta_value = '%s'
257
+ ", $item['sku']);
258
+ $found_product_id = $wpdb->get_var($db_query);
259
+ if ( ! $found_product_id ) {
260
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf(__( '> > Skipped. Cannot find product with sku %s. Importing instead.', 'wf_csv_import_export'), $item['sku']) );
261
+ $merging = false;
262
+
263
+ } else {
264
+
265
+ $post_id = $found_product_id;
266
+
267
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf(__( '> > Found product with ID %s.', 'wf_csv_import_export'), $post_id) );
268
+
269
+ }
270
+ }
271
+ $product['merging'] = true;
272
+ }
273
+ }
274
+
275
+ if ( ! $merging ) {
276
+
277
+ $product['merging'] = false;
278
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __('> Row %s - preparing for import.', 'wf_csv_import_export'), $this->row ) );
279
+
280
+ // Required fields
281
+ if ( $item['post_parent']=== '' && $item['post_title']=== '') {
282
+ $WF_CSV_Product_Import->log->add( 'csv-import', __( '> > Skipped. No post_title set for new product.', 'wf_csv_import_export') );
283
+ return new WP_Error( 'parse-error', __( 'No post_title set for new product.', 'wf_csv_import_export' ) );
284
+ }
285
+ if ( $item['post_parent']!== '' && $item['post_parent']!== null && $item['parent_sku'] === '' ) {
286
+ $WF_CSV_Product_Import->log->add( 'csv-import', __( '> > Skipped. No parent set for new variation product.', 'wf_csv_import_export') );
287
+ //return new WP_Error( 'parse-error', __( 'No post_title set for new product.', 'wf_csv_import_export' ) );
288
+ return new WP_Error( 'parse-error', __( 'No parent set for new variation product.', 'wf_csv_import_export' ) );
289
+ }
290
+
291
+ }
292
+
293
+ $product['post_id'] = $post_id;
294
+
295
+
296
+ // Get post fields
297
+ foreach ( $this->post_defaults as $column => $default ) {
298
+ if ( isset( $item[ $column ] ) ) $product[ $column ] = $item[ $column ];
299
+ }
300
+
301
+ // Get custom fields
302
+ foreach ( $this->postmeta_defaults as $column => $default ) {
303
+ if ( isset( $item[$column] ) )
304
+ $postmeta[$column] = (string) $item[$column];
305
+ elseif ( isset( $item['_' . $column] ) )
306
+ $postmeta[$column] = (string) $item['_' . $column];
307
+
308
+ // Check custom fields are valid
309
+ if ( isset( $postmeta[$column] ) && isset( $this->postmeta_allowed[$column] ) && ! in_array( $postmeta[$column], $this->postmeta_allowed[$column] ) ) {
310
+ $postmeta[$column] = $this->postmeta_defaults[$column];
311
+ }
312
+ }
313
+
314
+ if ( ! $merging ) {
315
+ // Merge post meta with defaults
316
+ $product = wp_parse_args( $product, $this->post_defaults );
317
+ $postmeta = wp_parse_args( $postmeta, $this->postmeta_defaults );
318
+ }
319
+
320
+ // Handle special meta fields
321
+ if ( isset($item['post_parent']) ) {
322
+
323
+ // price
324
+ if ( $merging ) {
325
+ if ( ! isset( $postmeta['regular_price'] ) )
326
+ $postmeta['regular_price'] = get_post_meta( $post_id, '_regular_price', true );
327
+ if ( ! isset( $postmeta['sale_price'] ) )
328
+ $postmeta['sale_price'] = get_post_meta( $post_id, '_sale_price', true );
329
+ }
330
+
331
+ if ( isset( $postmeta['regular_price'] ) && isset( $postmeta['sale_price'] ) && $postmeta['sale_price'] !== '' ) {
332
+ $price = min( $postmeta['sale_price'], $postmeta['regular_price']);
333
+ $postmeta['price'] = $price;
334
+ } elseif ( isset( $postmeta['regular_price'] ) ) {
335
+ $postmeta['price'] = $postmeta['regular_price'];
336
+ }
337
+
338
+ } else {
339
+
340
+ // price
341
+ if ( $merging ) {
342
+ if ( ! isset( $postmeta['regular_price'] ) )
343
+ $postmeta['regular_price'] = get_post_meta( $post_id, '_regular_price', true );
344
+ if ( ! isset( $postmeta['sale_price'] ) )
345
+ $postmeta['sale_price'] = get_post_meta( $post_id, '_sale_price', true );
346
+ }
347
+
348
+ if ( isset( $postmeta['regular_price'] ) && isset( $postmeta['sale_price'] ) && $postmeta['sale_price'] !== '' ) {
349
+ $price = min( $postmeta['sale_price'], $postmeta['regular_price']);
350
+ $postmeta['price'] = $price;
351
+ } elseif ( isset( $postmeta['regular_price'] ) ) {
352
+ $postmeta['price'] = $postmeta['regular_price'];
353
+ }
354
+
355
+ // Reset dynamically generated meta
356
+ $postmeta['min_variation_price'] = $postmeta['max_variation_price'] = $postmeta['min_variation_regular_price'] =$postmeta['max_variation_regular_price'] = $postmeta['min_variation_sale_price'] = $postmeta['max_variation_sale_price'] = '';
357
+ }
358
+
359
+ // upsells
360
+ if ( isset( $postmeta['upsell_ids'] ) && ! is_array( $postmeta['upsell_ids'] ) ) {
361
+ $ids = array_filter( array_map( 'trim', explode( '|', $postmeta['upsell_ids'] ) ) );
362
+ $postmeta['upsell_ids'] = $ids;
363
+ }
364
+
365
+ // crosssells
366
+ if ( isset( $postmeta['crosssell_ids'] ) && ! is_array( $postmeta['crosssell_ids'] ) ) {
367
+ $ids = array_filter( array_map( 'trim', explode( '|', $postmeta['crosssell_ids'] ) ) );
368
+ $postmeta['crosssell_ids'] = $ids;
369
+ }
370
+
371
+ // Sale dates
372
+ if ( isset( $postmeta['sale_price_dates_from'] ) ) {
373
+ $postmeta['sale_price_dates_from'] = empty( $postmeta['sale_price_dates_from'] ) ? '' : strtotime( $postmeta['sale_price_dates_from'] );
374
+ }
375
+
376
+ if ( isset( $postmeta['sale_price_dates_to'] ) ) {
377
+ $postmeta['sale_price_dates_to'] = empty( $postmeta['sale_price_dates_to'] ) ? '' : strtotime( $postmeta['sale_price_dates_to'] );
378
+ }
379
+
380
+ // Relative stock updates
381
+ if ( $merging ) {
382
+ if ( isset( $postmeta['stock'] ) ) {
383
+
384
+ $postmeta['stock'] = trim( $postmeta['stock'] );
385
+
386
+ $mode = substr( $postmeta['stock'], 0, 3 );
387
+
388
+ if ( $mode == '(+)' ) {
389
+ $old_stock = absint( get_post_meta( $post_id, '_stock', true ) );
390
+ $amount = absint( substr( $postmeta['stock'], 3 ) );
391
+ $new_stock = $old_stock + $amount;
392
+ $postmeta['stock'] = $new_stock;
393
+ }
394
+
395
+ if ( $mode == '(-)' ) {
396
+ $old_stock = absint( get_post_meta( $post_id, '_stock', true ) );
397
+ $amount = absint( substr( $postmeta['stock'], 3 ) );
398
+ $new_stock = $old_stock - $amount;
399
+ $postmeta['stock'] = $new_stock;
400
+ }
401
+ }
402
+ }
403
+
404
+ // Format post status
405
+ if ( ! empty( $product['post_status'] ) ) {
406
+ $product['post_status'] = strtolower( $product['post_status'] );
407
+
408
+ if ( empty($item['post_parent']) ) {
409
+ if ( ! in_array( $product['post_status'], array( 'publish', 'private', 'draft', 'pending', 'future', 'inherit', 'trash' ) ) ) {
410
+ $product['post_status'] = 'publish';
411
+ }
412
+ } else {
413
+ if ( ! in_array( $product['post_status'], array( 'private', 'publish' ) ) ) {
414
+ $product['post_status'] = 'publish';
415
+ }
416
+ }
417
+ }
418
+
419
+ // Put set core product postmeta into product array
420
+ foreach ( $postmeta as $key => $value ) {
421
+ $product['postmeta'][] = array( 'key' => '_' . esc_attr($key), 'value' => $value );
422
+ }
423
+
424
+ /**
425
+ * Handle other columns
426
+ */
427
+ foreach ( $item as $key => $value ) {
428
+
429
+ if ( empty($item['post_parent']) && ! $merge_empty_cells && $value == "" )
430
+ continue;
431
+
432
+ /**
433
+ * File path handling
434
+ */
435
+ if ( $key == 'file_paths' || $key == 'downloadable_files' ) {
436
+
437
+ $file_paths = explode( '|', $value );
438
+ $_file_paths = array();
439
+ foreach ( $file_paths as $file_path ) {
440
+ // 2.1
441
+ if ( function_exists( 'wc_get_filename_from_url' ) ) {
442
+ $file_path = array_map( 'trim', explode( '::', $file_path ) );
443
+ if ( sizeof( $file_path ) === 2 ) {
444
+ $file_name = $file_path[0];
445
+ $file_path = $file_path[1];
446
+ } else {
447
+ $file_name = wc_get_filename_from_url( $file_path[0] );
448
+ $file_path = $file_path[0];
449
+ }
450
+ $_file_paths[ md5( $file_path ) ] = array(
451
+ 'name' => $file_name,
452
+ 'file' => $file_path
453
+ );
454
+ } else {
455
+ $file_path = trim( $file_path );
456
+ $_file_paths[ md5( $file_path ) ] = $file_path;
457
+ }
458
+ }
459
+ $value = $_file_paths;
460
+
461
+ $product['postmeta'][] = array( 'key' => '_' . esc_attr( $key ), 'value' => $value );
462
+ }
463
+
464
+ /**
465
+ * Handle meta: columns for variation attributes
466
+ */
467
+ elseif ( strstr( $key, 'meta:attribute_pa_' ) ) {
468
+
469
+ // Get meta key name
470
+ $meta_key = ( isset( $WF_CSV_Product_Import->raw_headers[$key] ) ) ? $WF_CSV_Product_Import->raw_headers[$key] : $key;
471
+ $meta_key = trim( str_replace( 'meta:', '', $meta_key ) );
472
+
473
+ // Convert to slug
474
+ $value = sanitize_title( $value );
475
+
476
+ // Add to postmeta array
477
+ $product['postmeta'][] = array(
478
+ 'key' => esc_attr( $meta_key ),
479
+ 'value' => $value
480
+ );
481
+
482
+ }
483
+
484
+ /**
485
+ * Handle meta: columns - import as custom fields
486
+ */
487
+ elseif ( strstr( $key, 'meta:' ) ) {
488
+
489
+ // Get meta key name
490
+ $meta_key = ( isset( $WF_CSV_Product_Import->raw_headers[$key] ) ) ? $WF_CSV_Product_Import->raw_headers[$key] : $key;
491
+ $meta_key = trim( str_replace( 'meta:', '', $meta_key ) );
492
+
493
+ // Decode JSON
494
+ $json = json_decode( $value, true );
495
+
496
+ if ( is_array( $json ) || is_object( $json ) )
497
+ $value = (array) $json;
498
+
499
+ // Add to postmeta array
500
+ $product['postmeta'][] = array(
501
+ 'key' => esc_attr( $meta_key ),
502
+ 'value' => $value
503
+ );
504
+ }
505
+
506
+ /**
507
+ * Handle meta: columns - import as custom fields
508
+ */
509
+ elseif ( strstr( $key, 'tax:' ) ) {
510
+
511
+ // Get taxonomy
512
+ $taxonomy = trim( str_replace( 'tax:', '', $key ) );
513
+
514
+ // Exists?
515
+ if ( ! taxonomy_exists( $taxonomy ) ) {
516
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __('> > Skipping taxonomy "%s" - it does not exist.', 'wf_csv_import_export'), $taxonomy ) );
517
+ continue;
518
+ }
519
+
520
+ // Product type check
521
+ if ( $taxonomy == 'product_type' ) {
522
+ $term = strtolower( $value );
523
+
524
+ if ( ! array_key_exists( $term, $this->allowed_product_types ) ) {
525
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __('> > > Product type "%s" not allowed - using simple.', 'wf_csv_import_export'), $term ) );
526
+ $term_id = $this->allowed_product_types['simple'];
527
+ } else {
528
+ $term_id = $this->allowed_product_types[ $term ];
529
+ }
530
+
531
+ // Add to array
532
+ $terms_array[] = array(
533
+ 'taxonomy' => $taxonomy,
534
+ 'terms' => array( $term_id )
535
+ );
536
+
537
+ continue;
538
+ }
539
+
540
+ // Get terms - ID => parent
541
+ $terms = array();
542
+ $raw_terms = explode( '|', $value );
543
+ $raw_terms = array_map( 'trim', $raw_terms );
544
+
545
+ // Handle term hierachy (>)
546
+ foreach ( $raw_terms as $raw_term ) {
547
+
548
+ if ( strstr( $raw_term, '>' ) ) {
549
+
550
+ $raw_term = explode( '>', $raw_term );
551
+ $raw_term = array_map( 'trim', $raw_term );
552
+ $raw_term = array_map( 'wp_specialchars', $raw_term );
553
+ $raw_term = array_filter( $raw_term );
554
+
555
+ $parent = 0;
556
+ $loop = 0;
557
+
558
+ foreach ( $raw_term as $term ) {
559
+ $loop ++;
560
+ $term_id = '';
561
+
562
+ if ( isset( $this->inserted_terms[ $taxonomy ][ $parent ][ $term ] ) ) {
563
+ $term_id = $this->inserted_terms[ $taxonomy ][ $parent ][ $term ];
564
+ } elseif ( $term ) {
565
+
566
+ /**
567
+ * Check term existance
568
+ */
569
+ $term_may_exist = term_exists( $term, $taxonomy, absint( $parent ) );
570
+
571
+ $WF_CSV_Product_Import->log->add( 'CSV-Import', sprintf( __( '> > (' . __LINE__ . ') Term %s (%s) exists? %s', 'wf_csv_import_export' ), sanitize_text_field( $term ), esc_html( $taxonomy ), $term_may_exist ? print_r( $term_may_exist, true ) : '-' ) );
572
+
573
+ if ( is_array( $term_may_exist ) ) {
574
+ $possible_term = get_term( $term_may_exist['term_id'], 'product_cat' );
575
+
576
+ if ( $possible_term->parent == $parent ) {
577
+ $term_id = $term_may_exist['term_id'];
578
+ }
579
+ }
580
+
581
+ if ( ! $term_id ) {
582
+
583
+ // Create appropriate slug
584
+ $slug = array();
585
+
586
+ for ( $i = 0; $i < $loop; $i ++ )
587
+ $slug[] = $raw_term[ $i ];
588
+
589
+ $slug = sanitize_title( implode( '-', $slug ) );
590
+
591
+ $t = wp_insert_term( $term, $taxonomy, array( 'parent' => $parent, 'slug' => $slug ) );
592
+
593
+ if ( ! is_wp_error( $t ) ) {
594
+ $term_id = $t['term_id'];
595
+ } else {
596
+ $WF_CSV_Product_Import->log->add( 'CSV-Import', sprintf( __( '> > (' . __LINE__ . ') Failed to import term %s, parent %s - %s', 'wf_csv_import_export' ), sanitize_text_field( $term ), sanitize_text_field( $parent ), sanitize_text_field( $taxonomy ) ) );
597
+ break;
598
+ }
599
+ }
600
+
601
+ $this->inserted_terms[$taxonomy][$parent][$term] = $term_id;
602
+
603
+ }
604
+
605
+ if ( ! $term_id )
606
+ break;
607
+
608
+ // Add to product terms, ready to set if this is the final term
609
+ if ( sizeof( $raw_term ) == $loop )
610
+ $terms[] = $term_id;
611
+
612
+ $parent = $term_id;
613
+ }
614
+
615
+ } else {
616
+
617
+ $term_id = '';
618
+ $raw_term = wp_specialchars( $raw_term );
619
+
620
+ if ( isset( $this->inserted_terms[$taxonomy][0][$raw_term] ) ) {
621
+
622
+ $term_id = $this->inserted_terms[$taxonomy][0][$raw_term];
623
+
624
+ } elseif ( $raw_term ) {
625
+
626
+ // Check term existance
627
+ $term_exists = term_exists( $raw_term, $taxonomy, 0 );
628
+ $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : 0;
629
+
630
+ if ( ! $term_id ) {
631
+ $t = wp_insert_term( trim( $raw_term ), $taxonomy, array( 'parent' => 0 ) );
632
+
633
+ if ( ! is_wp_error( $t ) ) {
634
+ $term_id = $t['term_id'];
635
+ } else {
636
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __( '> > Failed to import term %s %s', 'wf_csv_import_export' ), esc_html($raw_term), esc_html($taxonomy) ) );
637
+ break;
638
+ }
639
+ }
640
+
641
+ $this->inserted_terms[$taxonomy][0][$raw_term] = $term_id;
642
+
643
+ }
644
+
645
+ // Store terms for later insertion
646
+ if ( $term_id )
647
+ $terms[] = $term_id;
648
+
649
+ }
650
+
651
+ }
652
+
653
+ // Any defined?
654
+ if ( sizeof( $terms ) == 0 )
655
+ continue;
656
+
657
+ // Add to array
658
+ $terms_array[] = array(
659
+ 'taxonomy' => $taxonomy,
660
+ 'terms' => $terms
661
+ );
662
+ }
663
+
664
+ /**
665
+ * Handle Attributes
666
+ */
667
+ elseif ( strstr( $key, 'attribute:' ) ) {
668
+
669
+ $attribute_key = sanitize_title( trim( str_replace( 'attribute:', '', $key ) ) );
670
+ $attribute_name = str_replace( 'attribute:', '', $WF_CSV_Product_Import->raw_headers[ $key ] );
671
+
672
+ if ( ! $attribute_key )
673
+ continue;
674
+
675
+ // Taxonomy
676
+ if ( substr( $attribute_key, 0, 3 ) == 'pa_' ) {
677
+
678
+ $taxonomy = $attribute_key;
679
+
680
+ // Exists?
681
+ if ( ! taxonomy_exists( $taxonomy ) ) {
682
+
683
+ $nicename = strtolower( sanitize_title( str_replace( 'pa_', '', $taxonomy ) ) );
684
+
685
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __('> > Attribute taxonomy "%s" does not exist. Adding it. Nicename: %s', 'wf_csv_import_export'), $taxonomy, $nicename ) );
686
+
687
+ $exists_in_db = $wpdb->get_var( "SELECT attribute_id FROM " . $wpdb->prefix . "woocommerce_attribute_taxonomies WHERE attribute_name = '" . $nicename . "';" );
688
+
689
+ if ( ! $exists_in_db ) {
690
+ // Create the taxonomy
691
+ $wpdb->insert( $wpdb->prefix . "woocommerce_attribute_taxonomies", array( 'attribute_name' => $nicename, 'attribute_label' => $nicename, 'attribute_type' => 'select', 'attribute_orderby' => 'menu_order' ) );
692
+ } else {
693
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __('> > Attribute taxonomy %s already exists in DB.', 'wf_csv_import_export'), $taxonomy ) );
694
+ }
695
+
696
+ // Register the taxonomy now so that the import works!
697
+ register_taxonomy( $taxonomy,
698
+ array( 'product', 'product_variation' ),
699
+ array(
700
+ 'hierarchical' => true,
701
+ 'show_ui' => false,
702
+ 'query_var' => true,
703
+ 'rewrite' => false,
704
+ )
705
+ );
706
+ }
707
+
708
+ // Get terms
709
+ $terms = array();
710
+ $raw_terms = explode( '|', $value );
711
+ $raw_terms = array_map( 'wp_specialchars', $raw_terms );
712
+ $raw_terms = array_map( 'trim', $raw_terms );
713
+
714
+ if ( sizeof( $raw_terms ) > 0 ) {
715
+
716
+ foreach ( $raw_terms as $raw_term ) {
717
+
718
+ if ( empty( $raw_term ) && 0 != $raw_term ) {
719
+ continue;
720
+ }
721
+
722
+ // Check term existance
723
+ $term_exists = term_exists( $raw_term, $taxonomy, 0 );
724
+ $term_id = is_array( $term_exists ) ? $term_exists['term_id'] : 0;
725
+
726
+ if ( ! $term_id ) {
727
+ $t = wp_insert_term( trim( $raw_term ), $taxonomy );
728
+
729
+ if ( ! is_wp_error( $t ) ) {
730
+ $term_id = $t['term_id'];
731
+
732
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __( '> > Inserted Raw Term %s ID = %s', 'wf_csv_import_export' ), esc_html( $raw_term ), $term_id ) );
733
+ } else {
734
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __( '> > Failed to import term %s %s', 'wf_csv_import_export' ), esc_html($raw_term), esc_html($taxonomy) ) );
735
+ break;
736
+ }
737
+ } else {
738
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __( '> > Raw Term %s ID = %s', 'wf_csv_import_export' ), esc_html( $raw_term ), $term_id ) );
739
+ }
740
+
741
+ if ( $term_id ) {
742
+ $terms[] = $term_id;
743
+ }
744
+ }
745
+
746
+ }
747
+
748
+ // Add to array
749
+ $terms_array[] = array(
750
+ 'taxonomy' => $taxonomy,
751
+ 'terms' => $terms
752
+ );
753
+
754
+ // Ensure we have original attributes
755
+ if ( is_null( $attributes ) && $merging ) {
756
+ $attributes = array_filter( (array) maybe_unserialize( get_post_meta( $post_id, '_product_attributes', true ) ) );
757
+ } elseif ( is_null( $attributes ) ) {
758
+ $attributes = array();
759
+ }
760
+
761
+ // Set attribute
762
+ if ( ! isset( $attributes[$taxonomy] ) )
763
+ $attributes[$taxonomy] = array();
764
+
765
+ $attributes[$taxonomy]['name'] = $taxonomy;
766
+ $attributes[$taxonomy]['value'] = null;
767
+ $attributes[$taxonomy]['is_taxonomy'] = 1;
768
+
769
+ if ( ! isset( $attributes[$taxonomy]['position'] ) )
770
+ $attributes[$taxonomy]['position'] = 0;
771
+ if ( ! isset( $attributes[$taxonomy]['is_visible'] ) )
772
+ $attributes[$taxonomy]['is_visible'] = 1;
773
+ if ( ! isset( $attributes[$taxonomy]['is_variation'] ) )
774
+ $attributes[$taxonomy]['is_variation'] = 0;
775
+
776
+ } else {
777
+
778
+ if ( ! $value || ! $attribute_key ) continue;
779
+
780
+ // Set attribute
781
+ if ( ! isset( $attributes[$attribute_key] ) )
782
+ $attributes[$attribute_key] = array();
783
+
784
+ $attributes[$attribute_key]['name'] = $attribute_name;
785
+ $attributes[$attribute_key]['value'] = $value;
786
+ $attributes[$attribute_key]['is_taxonomy'] = 0;
787
+
788
+ if ( ! isset( $attributes[$attribute_key]['position'] ) )
789
+ $attributes[$attribute_key]['position'] = 0;
790
+ if ( ! isset( $attributes[$attribute_key]['is_visible'] ) )
791
+ $attributes[$attribute_key]['is_visible'] = 1;
792
+ if ( ! isset( $attributes[$attribute_key]['is_variation'] ) )
793
+ $attributes[$attribute_key]['is_variation'] = 0;
794
+ }
795
+
796
+ }
797
+
798
+ /**
799
+ * Handle Attributes Data - position|is_visible|is_variation
800
+ */
801
+ elseif ( strstr( $key, 'attribute_data:' ) ) {
802
+
803
+ $attribute_key = sanitize_title( trim( str_replace( 'attribute_data:', '', $key ) ) );
804
+
805
+ if ( ! $attribute_key ) {
806
+ continue;
807
+ }
808
+
809
+ $values = explode( '|', $value );
810
+ $position = isset( $values[0] ) ? (int) $values[0] : 0;
811
+ $visible = isset( $values[1] ) ? (int) $values[1] : 1;
812
+ $variation = isset( $values[2] ) ? (int) $values[2] : 0;
813
+
814
+ // Ensure we have original attributes
815
+ if ( ! isset( $attributes[ $attribute_key ] ) ) {
816
+ if ( $merging ) {
817
+ $existing_attributes = array_filter( (array) maybe_unserialize( get_post_meta( $post_id, '_product_attributes', true ) ) );
818
+ $attributes[ $attribute_key ] = isset( $existing_attributes[ $attribute_key ] ) ? $existing_attributes[ $attribute_key ] : array();
819
+ } else {
820
+ $attributes[ $attribute_key ] = array();
821
+ }
822
+ }
823
+
824
+ $attributes[ $attribute_key ]['position'] = $position;
825
+ $attributes[ $attribute_key ]['is_visible'] = $visible;
826
+ $attributes[ $attribute_key ]['is_variation'] = $variation;
827
+ }
828
+
829
+ /**
830
+ * Handle Attributes Default Values
831
+ */
832
+ elseif ( strstr( $key, 'attribute_default:' ) ) {
833
+
834
+ $attribute_key = sanitize_title( trim( str_replace( 'attribute_default:', '', $key ) ) );
835
+
836
+ if ( ! $attribute_key ) continue;
837
+
838
+ // Ensure we have original attributes
839
+ if ( is_null( $default_attributes ) && $merging ) {
840
+ $default_attributes = array_filter( (array) maybe_unserialize( get_post_meta( $post_id, '_default_attributes', true ) ) );
841
+ } elseif ( is_null( $default_attributes ) ) {
842
+ $default_attributes = array();
843
+ }
844
+
845
+ $default_attributes[ $attribute_key ] = $value;
846
+ }
847
+
848
+ /**
849
+ * Handle gpf: google product feed columns
850
+ */
851
+ elseif ( strstr( $key, 'gpf:' ) ) {
852
+
853
+ $gpf_key = trim( str_replace( 'gpf:', '', $key ) );
854
+
855
+ // Get original values
856
+ if ( is_null( $gpf_data ) && $merging ) {
857
+ $gpf_data = array_filter( (array) maybe_unserialize( get_post_meta( $post_id, '_woocommerce_gpf_data', true ) ) );
858
+ } elseif ( is_null( $gpf_data ) ) {
859
+ $gpf_data = array(
860
+ 'availability' => '',
861
+ 'condition' => '',
862
+ 'brand' => '',
863
+ 'product_type' => '',
864
+ 'google_product_category' => '',
865
+ 'gtin' => '',
866
+ 'mpn' => '',
867
+ 'gender' => '',
868
+ 'age_group' => '',
869
+ 'color' => '',
870
+ 'size' => ''
871
+ );
872
+ }
873
+
874
+ $gpf_data[$gpf_key] = $value;
875
+
876
+ }
877
+
878
+ /**
879
+ * Handle parent_sku column for variations
880
+ */
881
+ elseif ( strstr( $key, 'parent_sku' ) ) {
882
+
883
+ if ( $value ) {
884
+ //$post_db_type = $this->post_defaults['post_type'];
885
+ //$post_pass_type = '"'.$post_db_type.'"';
886
+ $dbQuery = $wpdb->prepare("
887
+ SELECT $wpdb->posts.ID
888
+ FROM $wpdb->posts
889
+ LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
890
+ WHERE $wpdb->posts.post_type = 'product'
891
+ AND $wpdb->posts.post_status IN ( 'publish', 'private', 'draft' )
892
+ AND $wpdb->postmeta.meta_key = '_sku' AND $wpdb->postmeta.meta_value = '%s'
893
+ ", $value );
894
+ $found_product_id = $wpdb->get_var($dbQuery);
895
+ if ( $found_product_id )
896
+ $product['post_parent'] = $found_product_id;
897
+ }
898
+
899
+ }
900
+
901
+ /**
902
+ * Handle upsell SKUs which we cannot assign until we get IDs later on
903
+ */
904
+ elseif ( strstr( $key, 'upsell_skus' ) ) {
905
+ if ( $value ) {
906
+ $skus = array_filter( array_map( 'trim', explode( '|', $value ) ) );
907
+ $product['upsell_skus'] = $skus;
908
+ }
909
+ }
910
+
911
+ /**
912
+ * Handle crosssells SKUs which we cannot assign until we get IDs later on
913
+ */
914
+ elseif ( strstr( $key, 'crosssell_skus' ) ) {
915
+ if ( $value ) {
916
+ $skus = array_filter( array_map( 'trim', explode( '|', $value ) ) );
917
+ $product['crosssell_skus'] = $skus;
918
+ }
919
+ }
920
+
921
+ }
922
+
923
+ // Remove empty attribues
924
+ if(!empty($attributes))
925
+ foreach ( $attributes as $key => $value ) {
926
+ if ( ! isset($value['name']) ) unset( $attributes[$key] );
927
+ }
928
+
929
+ /**
930
+ * Handle images
931
+ */
932
+ if ( ! empty( $item['images'] ) ) {
933
+ $images = array_map( 'trim', explode( '|', $item['images'] ) );
934
+ } else {
935
+ $images = '';
936
+ }
937
+
938
+ $product['postmeta'][] = array( 'key' => '_default_attributes', 'value' => $default_attributes );
939
+ $product['attributes'] = $attributes;
940
+ $product['gpf_data'] = $gpf_data;
941
+ $product['images'] = $images;
942
+ $product['terms'] = $terms_array;
943
+ $product['sku'] = ( ! empty( $item['sku'] ) ) ? $item['sku'] : '';
944
+ $product['post_title'] = ( ! empty( $item['post_title'] ) ) ? $item['post_title'] : '';
945
+ unset( $item, $terms_array, $postmeta, $attributes, $gpf_data, $images );
946
+ return $product;
947
+ }
948
+ }
includes/importer/class-wf-prodimpexpcsv-importer.php ADDED
@@ -0,0 +1,61 @@
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
+
6
+ class WF_ProdImpExpCsv_Importer {
7
+
8
+ /**
9
+ * Product Exporter Tool
10
+ */
11
+ public static function load_wp_importer() {
12
+ // Load Importer API
13
+ require_once ABSPATH . 'wp-admin/includes/import.php';
14
+
15
+ if ( ! class_exists( 'WP_Importer' ) ) {
16
+ $class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
17
+ if ( file_exists( $class_wp_importer ) ) {
18
+ require $class_wp_importer;
19
+ }
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Product Importer Tool
25
+ */
26
+ public static function product_importer() {
27
+ if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) {
28
+ return;
29
+ }
30
+
31
+ self::load_wp_importer();
32
+
33
+ // includes
34
+ require_once 'class-wf-prodimpexpcsv-product-import.php';
35
+ require_once 'class-wf-csv-parser.php';
36
+
37
+ // Dispatch
38
+ $GLOBALS['WF_CSV_Product_Import'] = new WF_ProdImpExpCsv_Product_Import();
39
+ $GLOBALS['WF_CSV_Product_Import'] ->dispatch();
40
+ }
41
+
42
+ /**
43
+ * Variation Importer Tool
44
+ */
45
+ public static function variation_importer() {
46
+ if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) {
47
+ return;
48
+ }
49
+
50
+ self::load_wp_importer();
51
+
52
+ // includes
53
+ require 'class-wf-prodimpexpcsv-product-import.php';
54
+ //require 'class-wf-prodimpexpcsv-product_variation-import.php';
55
+ require 'class-wf-csv-parser.php';
56
+
57
+ // Dispatch
58
+ $GLOBALS['WF_CSV_Product_Import'] = new WC_ProdImpExpCsv_Product_Variation_Import();
59
+ $GLOBALS['WF_CSV_Product_Import'] ->dispatch();
60
+ }
61
+ }
includes/importer/class-wf-prodimpexpcsv-product-import.php ADDED
<
@@ -0,0 +1,1471 @@