diff --git a/assets/js/admin/wc-product-import.js b/assets/js/admin/wc-product-import.js index c707cb91fd7..2d6f0654a01 100644 --- a/assets/js/admin/wc-product-import.js +++ b/assets/js/admin/wc-product-import.js @@ -5,12 +5,13 @@ * productImportForm handles the import process. */ var productImportForm = function( $form ) { - this.$form = $form; - this.xhr = false; - this.mapping = wc_product_import_params.mapping; - this.position = 0; - this.file = wc_product_import_params.file; - this.security = wc_product_import_params.import_nonce; + this.$form = $form; + this.xhr = false; + this.mapping = wc_product_import_params.mapping; + this.position = 0; + this.file = wc_product_import_params.file; + this.skip_existing = wc_product_import_params.skip_existing; + this.security = wc_product_import_params.import_nonce; // Number of import successes/failures. this.imported = 0; @@ -35,11 +36,12 @@ type: 'POST', url: ajaxurl, data: { - action : 'woocommerce_do_ajax_product_import', - position : $this.position, - mapping : $this.mapping, - file : $this.file, - security : $this.security + action : 'woocommerce_do_ajax_product_import', + position : $this.position, + mapping : $this.mapping, + file : $this.file, + skip_existing : $this.skip_existing, + security : $this.security }, dataType: 'json', success: function( response ) { diff --git a/includes/admin/class-wc-admin-importers.php b/includes/admin/class-wc-admin-importers.php index 6acdaad55a4..35c397815ff 100644 --- a/includes/admin/class-wc-admin-importers.php +++ b/includes/admin/class-wc-admin-importers.php @@ -203,10 +203,11 @@ class WC_Admin_Importers { $file = wc_clean( $_POST['file'] ); $params = array( - 'start_pos' => isset( $_POST['position'] ) ? absint( $_POST['position'] ) : 0, - 'mapping' => isset( $_POST['mapping'] ) ? (array) $_POST['mapping'] : array(), - 'lines' => apply_filters( 'woocommerce_product_import_batch_size', 10 ), - 'parse' => true, + 'start_pos' => isset( $_POST['position'] ) ? absint( $_POST['position'] ) : 0, + 'mapping' => isset( $_POST['mapping'] ) ? (array) $_POST['mapping'] : array(), + 'skip_existing' => isset( $_POST['skip_existing'] ) ? (bool) $_POST['skip_existing'] : false, + 'lines' => apply_filters( 'woocommerce_product_import_batch_size', 10 ), + 'parse' => true, ); $importer = WC_Product_CSV_Importer_Controller::get_importer( $file, $params ); diff --git a/includes/admin/importers/class-wc-product-csv-importer-controller.php b/includes/admin/importers/class-wc-product-csv-importer-controller.php index b3718d787df..50a627f5206 100644 --- a/includes/admin/importers/class-wc-product-csv-importer-controller.php +++ b/includes/admin/importers/class-wc-product-csv-importer-controller.php @@ -52,6 +52,13 @@ class WC_Product_CSV_Importer_Controller { */ protected $delimiter = ','; + /** + * Whether to skip existing products. + * + * @var bool + */ + protected $skip_existing = false; + /** * Get importer instance. * @@ -92,6 +99,7 @@ class WC_Product_CSV_Importer_Controller { ); $this->step = isset( $_REQUEST['step'] ) ? sanitize_key( $_REQUEST['step'] ) : current( array_keys( $this->steps ) ); $this->file = isset( $_REQUEST['file'] ) ? wc_clean( $_REQUEST['file'] ) : ''; + $this->skip_existing = isset( $_REQUEST['skip_existing'] ) ? (bool) $_REQUEST['skip_existing'] : false; } /** @@ -119,10 +127,11 @@ class WC_Product_CSV_Importer_Controller { } $params = array( - 'step' => $keys[ $step_index + 1 ], - 'file' => $this->file, - 'delimiter' => $this->delimiter, - '_wpnonce' => wp_create_nonce( 'woocommerce-csv-importer' ), // wp_nonce_url() escapes & to & breaking redirects. + 'step' => $keys[ $step_index + 1 ], + 'file' => $this->file, + 'delimiter' => $this->delimiter, + 'skip_existing' => $this->skip_existing, + '_wpnonce' => wp_create_nonce( 'woocommerce-csv-importer' ), // wp_nonce_url() escapes & to & breaking redirects. ); return add_query_arg( $params ); @@ -300,9 +309,10 @@ class WC_Product_CSV_Importer_Controller { } wp_localize_script( 'wc-product-import', 'wc_product_import_params', array( - 'import_nonce' => wp_create_nonce( 'wc-product-import' ), - 'mapping' => $mapping, - 'file' => $this->file, + 'import_nonce' => wp_create_nonce( 'wc-product-import' ), + 'mapping' => $mapping, + 'file' => $this->file, + 'skip_existing' => $this->skip_existing, ) ); wp_enqueue_script( 'wc-product-import' ); diff --git a/includes/admin/importers/views/html-csv-import-mapping.php b/includes/admin/importers/views/html-csv-import-mapping.php index 12543f233d0..8209e34573c 100644 --- a/includes/admin/importers/views/html-csv-import-mapping.php +++ b/includes/admin/importers/views/html-csv-import-mapping.php @@ -54,6 +54,7 @@ if ( ! defined( 'ABSPATH' ) ) { + diff --git a/includes/admin/importers/views/html-product-csv-import-form.php b/includes/admin/importers/views/html-product-csv-import-form.php index 45c50521b51..e04ffb00006 100644 --- a/includes/admin/importers/views/html-product-csv-import-form.php +++ b/includes/admin/importers/views/html-product-csv-import-form.php @@ -56,6 +56,13 @@ if ( ! defined( 'ABSPATH' ) ) {
+ +
+ + + + + diff --git a/includes/import/abstract-wc-product-importer.php b/includes/import/abstract-wc-product-importer.php index 978f5fe5ee8..d12748f5d57 100644 --- a/includes/import/abstract-wc-product-importer.php +++ b/includes/import/abstract-wc-product-importer.php @@ -138,12 +138,8 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { * @return WC_Product|WC_Error */ protected function process_item( $data ) { - // Ignore IDs and create new products. - // @todo Mike said that we should have something to force create. - $force_create = false; - try { - $object = $this->prepare_product( $data, $force_create ); + $object = $this->prepare_product( $data ); if ( is_wp_error( $object ) ) { return $object; @@ -182,11 +178,10 @@ abstract class WC_Product_Importer implements WC_Importer_Interface { * Prepare a single product for create or update. * * @param array $data Row data. - * @param bool $creating If should force create a new product. * @return WC_Product|WP_Error */ - protected function prepare_product( $data, $force_create = false ) { - $id = ! $force_create && isset( $data['id'] ) ? absint( $data['id'] ) : 0; + protected function prepare_product( $data ) { + $id = isset( $data['id'] ) ? absint( $data['id'] ) : 0; // Type is the most important part here because we need to be using the correct class and methods. if ( isset( $data['type'] ) ) { diff --git a/includes/import/class-wc-product-csv-importer.php b/includes/import/class-wc-product-csv-importer.php index 97c97ba19e8..c8c73f782a3 100644 --- a/includes/import/class-wc-product-csv-importer.php +++ b/includes/import/class-wc-product-csv-importer.php @@ -31,12 +31,13 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { */ public function __construct( $file, $params = array() ) { $default_args = array( - 'start_pos' => 0, // File pointer start. - 'end_pos' => -1, // File pointer end. - 'lines' => -1, // Max lines to read. - 'mapping' => array(), // Column mapping. csv_heading => schema_heading. - 'parse' => false, // Whether to sanitize and format data. - 'delimiter' => ',', // CSV delimiter. + 'start_pos' => 0, // File pointer start. + 'end_pos' => -1, // File pointer end. + 'lines' => -1, // Max lines to read. + 'mapping' => array(), // Column mapping. csv_heading => schema_heading. + 'parse' => false, // Whether to sanitize and format data. + 'skip_existing' => false, // Whether to skip existing items. + 'delimiter' => ',', // CSV delimiter. ); $this->params = wp_parse_args( $params, $default_args ); @@ -270,6 +271,21 @@ class WC_Product_CSV_Importer extends WC_Product_Importer { ); foreach ( $this->parsed_data as $parsed_data ) { + + // Don't import products with IDs or SKUs that already exist if option is true. + if ( $this->params['skip_existing'] ) { + $id = isset( $parsed_data['id'] ) ? absint( $parsed_data['id'] ) : 0; + $sku = isset( $parsed_data['sku'] ) ? esc_attr( $parsed_data['sku'] ) : 0; + + if ( $id && wc_get_product( $id ) ) { + $data['failed'][] = new WP_Error( 'woocommerce_product_csv_importer_error', __( 'A product with this ID already exists.', 'woocommerce' ), array( 'id' => $id ) ); + continue; + } elseif( $sku && wc_get_product_id_by_sku( $sku ) ) { + $data['failed'][] = new WP_Error( 'woocommerce_product_csv_importer_error', __( 'A product with this SKU already exists.', 'woocommerce' ), array( 'sku' => $sku ) ); + continue; + } + } + $result = $this->process_item( $parsed_data ); if ( is_wp_error( $result ) ) {