Merge pull request #15189 from woocommerce/feature/import-merges-2
Add "Skip existing products" option.
This commit is contained in:
commit
076eac48b5
|
@ -5,12 +5,13 @@
|
||||||
* productImportForm handles the import process.
|
* productImportForm handles the import process.
|
||||||
*/
|
*/
|
||||||
var productImportForm = function( $form ) {
|
var productImportForm = function( $form ) {
|
||||||
this.$form = $form;
|
this.$form = $form;
|
||||||
this.xhr = false;
|
this.xhr = false;
|
||||||
this.mapping = wc_product_import_params.mapping;
|
this.mapping = wc_product_import_params.mapping;
|
||||||
this.position = 0;
|
this.position = 0;
|
||||||
this.file = wc_product_import_params.file;
|
this.file = wc_product_import_params.file;
|
||||||
this.security = wc_product_import_params.import_nonce;
|
this.skip_existing = wc_product_import_params.skip_existing;
|
||||||
|
this.security = wc_product_import_params.import_nonce;
|
||||||
|
|
||||||
// Number of import successes/failures.
|
// Number of import successes/failures.
|
||||||
this.imported = 0;
|
this.imported = 0;
|
||||||
|
@ -35,11 +36,12 @@
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: ajaxurl,
|
url: ajaxurl,
|
||||||
data: {
|
data: {
|
||||||
action : 'woocommerce_do_ajax_product_import',
|
action : 'woocommerce_do_ajax_product_import',
|
||||||
position : $this.position,
|
position : $this.position,
|
||||||
mapping : $this.mapping,
|
mapping : $this.mapping,
|
||||||
file : $this.file,
|
file : $this.file,
|
||||||
security : $this.security
|
skip_existing : $this.skip_existing,
|
||||||
|
security : $this.security
|
||||||
},
|
},
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function( response ) {
|
success: function( response ) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
!function(a,b){var c=function(a){this.$form=a,this.xhr=!1,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.imported=0,this.failed=0,this.$form.find(".woocommerce-importer-progress").val(0),this.run_import=this.run_import.bind(this),this.run_import()};c.prototype.run_import=function(){var c=this;a.ajax({type:"POST",url:ajaxurl,data:{action:"woocommerce_do_ajax_product_import",position:c.position,mapping:c.mapping,file:c.file,security:c.security},dataType:"json",success:function(a){a.success&&(c.position=a.data.position,c.imported+=a.data.imported,c.failed+=a.data.failed,c.$form.find(".woocommerce-importer-progress").val(a.data.percentage),"done"===a.data.position?b.location=a.data.url+"&imported="+parseInt(c.imported,10)+"&failed="+parseInt(c.failed,10):c.run_import())}}).fail(function(a){b.console.log(a)})},a.fn.wc_product_importer=function(){return new c(this),this},a(".woocommerce-importer").wc_product_importer()}(jQuery,window);
|
!function(a,b){var c=function(a){this.$form=a,this.xhr=!1,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,this.imported=0,this.failed=0,this.$form.find(".woocommerce-importer-progress").val(0),this.run_import=this.run_import.bind(this),this.run_import()};c.prototype.run_import=function(){var c=this;a.ajax({type:"POST",url:ajaxurl,data:{action:"woocommerce_do_ajax_product_import",position:c.position,mapping:c.mapping,file:c.file,skip_existing:c.skip_existing,security:c.security},dataType:"json",success:function(a){a.success&&(c.position=a.data.position,c.imported+=a.data.imported,c.failed+=a.data.failed,c.$form.find(".woocommerce-importer-progress").val(a.data.percentage),"done"===a.data.position?b.location=a.data.url+"&imported="+parseInt(c.imported,10)+"&failed="+parseInt(c.failed,10):c.run_import())}}).fail(function(a){b.console.log(a)})},a.fn.wc_product_importer=function(){return new c(this),this},a(".woocommerce-importer").wc_product_importer()}(jQuery,window);
|
|
@ -203,10 +203,11 @@ class WC_Admin_Importers {
|
||||||
|
|
||||||
$file = wc_clean( $_POST['file'] );
|
$file = wc_clean( $_POST['file'] );
|
||||||
$params = array(
|
$params = array(
|
||||||
'start_pos' => isset( $_POST['position'] ) ? absint( $_POST['position'] ) : 0,
|
'start_pos' => isset( $_POST['position'] ) ? absint( $_POST['position'] ) : 0,
|
||||||
'mapping' => isset( $_POST['mapping'] ) ? (array) $_POST['mapping'] : array(),
|
'mapping' => isset( $_POST['mapping'] ) ? (array) $_POST['mapping'] : array(),
|
||||||
'lines' => apply_filters( 'woocommerce_product_import_batch_size', 10 ),
|
'skip_existing' => isset( $_POST['skip_existing'] ) ? (bool) $_POST['skip_existing'] : false,
|
||||||
'parse' => true,
|
'lines' => apply_filters( 'woocommerce_product_import_batch_size', 10 ),
|
||||||
|
'parse' => true,
|
||||||
);
|
);
|
||||||
|
|
||||||
$importer = WC_Product_CSV_Importer_Controller::get_importer( $file, $params );
|
$importer = WC_Product_CSV_Importer_Controller::get_importer( $file, $params );
|
||||||
|
|
|
@ -52,6 +52,13 @@ class WC_Product_CSV_Importer_Controller {
|
||||||
*/
|
*/
|
||||||
protected $delimiter = ',';
|
protected $delimiter = ',';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to skip existing products.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $skip_existing = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get importer instance.
|
* 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->step = isset( $_REQUEST['step'] ) ? sanitize_key( $_REQUEST['step'] ) : current( array_keys( $this->steps ) );
|
||||||
$this->file = isset( $_REQUEST['file'] ) ? wc_clean( $_REQUEST['file'] ) : '';
|
$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(
|
$params = array(
|
||||||
'step' => $keys[ $step_index + 1 ],
|
'step' => $keys[ $step_index + 1 ],
|
||||||
'file' => $this->file,
|
'file' => $this->file,
|
||||||
'delimiter' => $this->delimiter,
|
'delimiter' => $this->delimiter,
|
||||||
'_wpnonce' => wp_create_nonce( 'woocommerce-csv-importer' ), // wp_nonce_url() escapes & to & breaking redirects.
|
'skip_existing' => $this->skip_existing,
|
||||||
|
'_wpnonce' => wp_create_nonce( 'woocommerce-csv-importer' ), // wp_nonce_url() escapes & to & breaking redirects.
|
||||||
);
|
);
|
||||||
|
|
||||||
return add_query_arg( $params );
|
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(
|
wp_localize_script( 'wc-product-import', 'wc_product_import_params', array(
|
||||||
'import_nonce' => wp_create_nonce( 'wc-product-import' ),
|
'import_nonce' => wp_create_nonce( 'wc-product-import' ),
|
||||||
'mapping' => $mapping,
|
'mapping' => $mapping,
|
||||||
'file' => $this->file,
|
'file' => $this->file,
|
||||||
|
'skip_existing' => $this->skip_existing,
|
||||||
) );
|
) );
|
||||||
wp_enqueue_script( 'wc-product-import' );
|
wp_enqueue_script( 'wc-product-import' );
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||||
<input type="submit" class="button button-primary button-next" value="<?php esc_attr_e( 'Run the importer', 'woocommerce' ); ?>" name="save_step" />
|
<input type="submit" class="button button-primary button-next" value="<?php esc_attr_e( 'Run the importer', 'woocommerce' ); ?>" name="save_step" />
|
||||||
<input type="hidden" name="file" value="<?php echo esc_attr( $this->file ); ?>" />
|
<input type="hidden" name="file" value="<?php echo esc_attr( $this->file ); ?>" />
|
||||||
<input type="hidden" name="delimiter" value="<?php echo esc_attr( $this->delimiter ); ?>" />
|
<input type="hidden" name="delimiter" value="<?php echo esc_attr( $this->delimiter ); ?>" />
|
||||||
|
<input type="hidden" name="skip_existing" value="<?php echo (int) $this->skip_existing; ?>" />
|
||||||
<?php wp_nonce_field( 'woocommerce-csv-importer' ); ?>
|
<?php wp_nonce_field( 'woocommerce-csv-importer' ); ?>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -56,6 +56,13 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||||
<th><label><?php _e( 'CSV Delimiter', 'woocommerce' ); ?></label><br/></th>
|
<th><label><?php _e( 'CSV Delimiter', 'woocommerce' ); ?></label><br/></th>
|
||||||
<td><input type="text" name="delimiter" placeholder="," size="2" /></td>
|
<td><input type="text" name="delimiter" placeholder="," size="2" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e( 'Skip existing products', 'woocommerce' ); ?></label><br/></th>
|
||||||
|
<td>
|
||||||
|
<input type="hidden" name="skip_existing" value="0" />
|
||||||
|
<input type="checkbox" name="skip_existing" value="1" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -138,12 +138,8 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
|
||||||
* @return WC_Product|WC_Error
|
* @return WC_Product|WC_Error
|
||||||
*/
|
*/
|
||||||
protected function process_item( $data ) {
|
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 {
|
try {
|
||||||
$object = $this->prepare_product( $data, $force_create );
|
$object = $this->prepare_product( $data );
|
||||||
|
|
||||||
if ( is_wp_error( $object ) ) {
|
if ( is_wp_error( $object ) ) {
|
||||||
return $object;
|
return $object;
|
||||||
|
@ -182,11 +178,10 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
|
||||||
* Prepare a single product for create or update.
|
* Prepare a single product for create or update.
|
||||||
*
|
*
|
||||||
* @param array $data Row data.
|
* @param array $data Row data.
|
||||||
* @param bool $creating If should force create a new product.
|
|
||||||
* @return WC_Product|WP_Error
|
* @return WC_Product|WP_Error
|
||||||
*/
|
*/
|
||||||
protected function prepare_product( $data, $force_create = false ) {
|
protected function prepare_product( $data ) {
|
||||||
$id = ! $force_create && isset( $data['id'] ) ? absint( $data['id'] ) : 0;
|
$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.
|
// Type is the most important part here because we need to be using the correct class and methods.
|
||||||
if ( isset( $data['type'] ) ) {
|
if ( isset( $data['type'] ) ) {
|
||||||
|
|
|
@ -31,12 +31,13 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
|
||||||
*/
|
*/
|
||||||
public function __construct( $file, $params = array() ) {
|
public function __construct( $file, $params = array() ) {
|
||||||
$default_args = array(
|
$default_args = array(
|
||||||
'start_pos' => 0, // File pointer start.
|
'start_pos' => 0, // File pointer start.
|
||||||
'end_pos' => -1, // File pointer end.
|
'end_pos' => -1, // File pointer end.
|
||||||
'lines' => -1, // Max lines to read.
|
'lines' => -1, // Max lines to read.
|
||||||
'mapping' => array(), // Column mapping. csv_heading => schema_heading.
|
'mapping' => array(), // Column mapping. csv_heading => schema_heading.
|
||||||
'parse' => false, // Whether to sanitize and format data.
|
'parse' => false, // Whether to sanitize and format data.
|
||||||
'delimiter' => ',', // CSV delimiter.
|
'skip_existing' => false, // Whether to skip existing items.
|
||||||
|
'delimiter' => ',', // CSV delimiter.
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->params = wp_parse_args( $params, $default_args );
|
$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 ) {
|
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'] ) : '';
|
||||||
|
|
||||||
|
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 );
|
$result = $this->process_item( $parsed_data );
|
||||||
|
|
||||||
if ( is_wp_error( $result ) ) {
|
if ( is_wp_error( $result ) ) {
|
||||||
|
|
Loading…
Reference in New Issue