Product Import Export for WooCommerce - Version 1.0.1

Version Description

  • Bug Fix: Fixed issue with Evaluation field with single quotes.
  • Bug Fix: Option to import gallery images.
  • Enhancement: Improved help text for Post name and Stock quantity.
  • Enhancement: Improved label text for Product type, category , tags and shipping class.
  • Enhancement: Included links to Documentation and sample CSV.
Download this release

Release Info

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

Code changes from version 1.0.0 to 1.0.1

Files changed (31) hide show
  1. images/wf-ajax-loader.gif +0 -0
  2. images/wf-failed.png +0 -0
  3. images/wf-import.png +0 -0
  4. images/wf-notice.png +0 -0
  5. images/wf-success.png +0 -0
  6. includes/class-wf-prodimpexpcsv-admin-screen.php +82 -83
  7. includes/class-wf-prodimpexpcsv-ajax-handler.php +68 -68
  8. includes/class-wf-prodimpexpcsv-system-status-tools.php +102 -102
  9. includes/exporter/class-wf-prodimpexpcsv-exporter.php +530 -530
  10. includes/exporter/data/data-wf-hidden-meta-columns.php +19 -19
  11. includes/exporter/data/data-wf-post-columns.php +50 -50
  12. includes/importer/class-wf-csv-parser.php +879 -948
  13. includes/importer/class-wf-prodimpexpcsv-importer.php +40 -60
  14. includes/importer/class-wf-prodimpexpcsv-product-import.php +1470 -1470
  15. includes/importer/data/data-wf-post-defaults.php +21 -21
  16. includes/importer/data/data-wf-postmeta-allowed.php +15 -15
  17. includes/importer/data/data-wf-postmeta-defaults.php +43 -43
  18. includes/importer/data/data-wf-reserved-fields-pair.php +51 -47
  19. includes/importer/data/data-wf-reserved-fields.php +59 -59
  20. includes/importer/views/html-wf-import-greeting.php +54 -54
  21. includes/importer/views/html-wf-import-options.php +114 -97
  22. includes/settings/class-wf-prodimpexpcsv-settings.php +20 -20
  23. includes/views/export/html-wf-export-products.php +73 -73
  24. includes/views/html-wf-admin-screen.php +19 -19
  25. includes/views/html-wf-getting-started.php +0 -8
  26. includes/views/import/html-wf-import-products.php +45 -33
  27. license.txt +707 -707
  28. product-csv-import-export.php +136 -139
  29. readme.txt +18 -4
  30. sample.csv +2 -0
  31. styles/wf-style.css +96 -102
images/wf-ajax-loader.gif CHANGED
File without changes
images/wf-failed.png CHANGED
File without changes
images/wf-import.png CHANGED
File without changes
images/wf-notice.png CHANGED
File without changes
images/wf-success.png CHANGED
File without changes
includes/class-wf-prodimpexpcsv-admin-screen.php CHANGED
@@ -1,84 +1,83 @@
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();
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/import/html-wf-import-products.php' );
64
+ $post_columns = include( 'exporter/data/data-wf-post-columns.php' );
65
+ include( 'views/export/html-wf-export-products.php' );
66
+ }
67
+
68
+ /**
69
+ * Admin Page for exporting
70
+ */
71
+ public function admin_export_page() {
72
+ $post_columns = include( 'exporter/data/data-wf-post-columns.php' );
73
+ include( 'views/export/html-wf-export-products.php' );
74
+ }
75
+
76
+ /**
77
+ * Admin Page for settings
78
+ */
79
+ public function admin_settings_page() {
80
+ }
81
+ }
82
+
83
new WF_ProdImpExpCsv_Admin_Screen();
includes/class-wf-prodimpexpcsv-ajax-handler.php CHANGED
@@ -1,69 +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();
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 CHANGED
@@ -1,103 +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();
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 CHANGED
@@ -1,530 +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
- }
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 CHANGED
@@ -1,20 +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
);
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 CHANGED
@@ -1,51 +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
) );
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 CHANGED
@@ -1,948 +1,879 @@
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
- }
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
+ $this->post_type = 'product';
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
+ // Check product to merge exists
248
+ $db_query = $wpdb->prepare("
249
+ SELECT $wpdb->posts.ID
250
+ FROM $wpdb->posts
251
+ LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
252
+ WHERE $wpdb->posts.post_type = 'product'
253
+ AND $wpdb->posts.post_status IN ( 'publish', 'private', 'draft', 'pending', 'future' )
254
+ AND $wpdb->postmeta.meta_key = '_sku' AND $wpdb->postmeta.meta_value = '%s'
255
+ ", $item['sku']);
256
+ $found_product_id = $wpdb->get_var($db_query);
257
+ if ( ! $found_product_id ) {
258
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf(__( '> > Skipped. Cannot find product with sku %s. Importing instead.', 'wf_csv_import_export'), $item['sku']) );
259
+ $merging = false;
260
+
261
+ } else {
262
+
263
+ $post_id = $found_product_id;
264
+
265
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf(__( '> > Found product with ID %s.', 'wf_csv_import_export'), $post_id) );
266
+
267
+ }
268
+ }
269
+ $product['merging'] = true;
270
+ }
271
+ }
272
+
273
+ if ( ! $merging ) {
274
+
275
+ $product['merging'] = false;
276
+ $WF_CSV_Product_Import->log->add( 'csv-import', sprintf( __('> Row %s - preparing for import.', 'wf_csv_import_export'), $this->row ) );
277
+
278
+ // Required fields
279
+ if ( $item['post_parent']=== '' && $item['post_title']=== '') {
280
+ $WF_CSV_Product_Import->log->add( 'csv-import', __( '> > Skipped. No post_title set for new product.', 'wf_csv_import_export') );
281
+ return new WP_Error( 'parse-error', __( 'No post_title set for new product.', 'wf_csv_import_export' ) );
282
+ }
283
+ if ( $item['post_parent']!== '' && $item['post_parent']!== null && $item['parent_sku'] === '' ) {
284
+ $WF_CSV_Product_Import->log->add( 'csv-import', __( '> > Skipped. No parent set for new variation product.', 'wf_csv_import_export') );
285
+ //return new WP_Error( 'parse-error', __( 'No post_title set for new product.', 'wf_csv_import_export' ) );
286
+ return new WP_Error( 'parse-error', __( 'No parent set for new variation product.', 'wf_csv_import_export' ) );
287
+ }
288
+
289
+ }
290
+
291
+ $product['post_id'] = $post_id;
292
+
293
+
294
+ // Get post fields
295
+ foreach ( $this->post_defaults as $column => $default ) {
296
+ if