2013-07-24 16:01:36 +00:00
< ? php
/**
2017-05-17 10:24:27 +00:00
* Init WooCommerce data importers .
2013-07-24 16:01:36 +00:00
*
2018-03-13 11:11:11 +00:00
* @ package WooCommerce / Admin
2013-07-24 16:01:36 +00:00
*/
2018-03-13 11:11:11 +00:00
defined ( 'ABSPATH' ) || exit ;
2013-07-24 16:01:36 +00:00
/**
2015-11-03 12:28:01 +00:00
* WC_Admin_Importers Class .
2013-07-24 16:01:36 +00:00
*/
class WC_Admin_Importers {
/**
2017-05-17 10:24:27 +00:00
* Array of importer IDs .
*
* @ var string []
*/
protected $importers = array ();
/**
* Constructor .
2013-07-24 16:01:36 +00:00
*/
public function __construct () {
2018-04-04 13:06:13 +00:00
if ( ! $this -> import_allowed () ) {
return ;
}
2017-05-17 10:24:27 +00:00
add_action ( 'admin_menu' , array ( $this , 'add_to_menus' ) );
2013-07-24 16:01:36 +00:00
add_action ( 'admin_init' , array ( $this , 'register_importers' ) );
2017-05-17 10:24:27 +00:00
add_action ( 'admin_head' , array ( $this , 'hide_from_menus' ) );
2017-05-17 21:34:49 +00:00
add_action ( 'admin_enqueue_scripts' , array ( $this , 'admin_scripts' ) );
add_action ( 'wp_ajax_woocommerce_do_ajax_product_import' , array ( $this , 'do_ajax_product_import' ) );
2017-05-17 10:24:27 +00:00
// Register WooCommerce importers.
$this -> importers [ 'product_importer' ] = array (
'menu' => 'edit.php?post_type=product' ,
'name' => __ ( 'Product Import' , 'woocommerce' ),
2018-04-04 08:30:49 +00:00
'capability' => 'import' ,
2017-05-17 10:24:27 +00:00
'callback' => array ( $this , 'product_importer' ),
);
2013-07-24 16:01:36 +00:00
}
2018-04-04 13:06:13 +00:00
/**
* Return true if WooCommerce imports are allowed for current user , false otherwise .
*
* @ return bool Whether current user can perform imports .
*/
protected function import_allowed () {
return current_user_can ( 'edit_products' ) && current_user_can ( 'import' );
}
2013-07-24 16:01:36 +00:00
/**
2017-05-17 10:24:27 +00:00
* Add menu items for our custom importers .
2013-07-24 16:01:36 +00:00
*/
2017-05-17 10:24:27 +00:00
public function add_to_menus () {
foreach ( $this -> importers as $id => $importer ) {
add_submenu_page ( $importer [ 'menu' ], $importer [ 'name' ], $importer [ 'name' ], $importer [ 'capability' ], $id , $importer [ 'callback' ] );
}
}
/**
* Hide menu items from view so the pages exist , but the menu items do not .
*/
public function hide_from_menus () {
global $submenu ;
foreach ( $this -> importers as $id => $importer ) {
if ( isset ( $submenu [ $importer [ 'menu' ] ] ) ) {
foreach ( $submenu [ $importer [ 'menu' ] ] as $key => $menu ) {
if ( $id === $menu [ 2 ] ) {
unset ( $submenu [ $importer [ 'menu' ] ][ $key ] );
}
}
}
}
2013-07-24 16:01:36 +00:00
}
2017-05-17 21:34:49 +00:00
/**
* Register importer scripts .
*/
public function admin_scripts () {
$suffix = defined ( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ;
2017-05-17 21:43:03 +00:00
wp_register_script ( 'wc-product-import' , WC () -> plugin_url () . '/assets/js/admin/wc-product-import' . $suffix . '.js' , array ( 'jquery' ), WC_VERSION );
2017-05-17 21:34:49 +00:00
}
2013-07-24 16:01:36 +00:00
/**
2017-05-17 10:24:27 +00:00
* The product importer .
*
* This has a custom screen - the Tools > Import item is a placeholder .
* If we ' re on that screen , redirect to the custom one .
2017-05-01 21:30:45 +00:00
*/
public function product_importer () {
2017-05-17 10:24:27 +00:00
if ( defined ( 'WP_LOAD_IMPORTERS' ) ) {
wp_safe_redirect ( admin_url ( 'edit.php?post_type=product&page=product_importer' ) );
exit ;
}
2018-03-05 18:59:17 +00:00
include_once WC_ABSPATH . 'includes/import/class-wc-product-csv-importer.php' ;
include_once WC_ABSPATH . 'includes/admin/importers/class-wc-product-csv-importer-controller.php' ;
2017-05-01 21:30:45 +00:00
2017-05-17 13:16:38 +00:00
$importer = new WC_Product_CSV_Importer_Controller ();
2017-05-01 21:30:45 +00:00
$importer -> dispatch ();
}
/**
2017-05-17 10:24:27 +00:00
* Register WordPress based importers .
*/
public function register_importers () {
if ( defined ( 'WP_LOAD_IMPORTERS' ) ) {
add_action ( 'import_start' , array ( $this , 'post_importer_compatibility' ) );
2018-03-05 18:59:17 +00:00
register_importer ( 'woocommerce_product_csv' , __ ( 'WooCommerce products (CSV)' , 'woocommerce' ), __ ( 'Import <strong>products</strong> to your store via a csv file.' , 'woocommerce' ), array ( $this , 'product_importer' ) );
2017-05-17 10:24:27 +00:00
register_importer ( 'woocommerce_tax_rate_csv' , __ ( 'WooCommerce tax rates (CSV)' , 'woocommerce' ), __ ( 'Import <strong>tax rates</strong> to your store via a csv file.' , 'woocommerce' ), array ( $this , 'tax_rates_importer' ) );
}
}
/**
* The tax rate importer which extends WP_Importer .
2013-07-24 16:01:36 +00:00
*/
public function tax_rates_importer () {
require_once ABSPATH . 'wp-admin/includes/import.php' ;
if ( ! class_exists ( 'WP_Importer' ) ) {
$class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php' ;
2014-11-30 06:52:32 +00:00
if ( file_exists ( $class_wp_importer ) ) {
2013-07-24 16:01:36 +00:00
require $class_wp_importer ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
}
2018-03-05 18:59:17 +00:00
require dirname ( __FILE__ ) . '/importers/class-wc-tax-rate-importer.php' ;
2013-07-24 16:01:36 +00:00
2013-07-24 18:55:02 +00:00
$importer = new WC_Tax_Rate_Importer ();
$importer -> dispatch ();
2013-07-24 16:01:36 +00:00
}
/**
2017-05-17 10:24:27 +00:00
* When running the WP XML importer , ensure attributes exist .
2013-07-24 16:01:36 +00:00
*
* WordPress import should work - however , it fails to import custom product attribute taxonomies .
* This code grabs the file before it is imported and ensures the taxonomies are created .
*/
public function post_importer_compatibility () {
global $wpdb ;
2018-03-13 11:11:11 +00:00
if ( empty ( $_POST [ 'import_id' ] ) || ! class_exists ( 'WXR_Parser' ) ) { // PHPCS: input var ok, CSRF ok.
2013-07-24 16:01:36 +00:00
return ;
2014-11-30 06:52:32 +00:00
}
2013-07-24 16:01:36 +00:00
2018-03-13 11:11:11 +00:00
$id = absint ( $_POST [ 'import_id' ] ); // PHPCS: input var ok.
2013-07-24 16:01:36 +00:00
$file = get_attached_file ( $id );
$parser = new WXR_Parser ();
$import_data = $parser -> parse ( $file );
2017-05-17 10:24:27 +00:00
if ( isset ( $import_data [ 'posts' ] ) && ! empty ( $import_data [ 'posts' ] ) ) {
foreach ( $import_data [ 'posts' ] as $post ) {
if ( 'product' === $post [ 'post_type' ] && ! empty ( $post [ 'terms' ] ) ) {
foreach ( $post [ 'terms' ] as $term ) {
if ( strstr ( $term [ 'domain' ], 'pa_' ) ) {
if ( ! taxonomy_exists ( $term [ 'domain' ] ) ) {
$attribute_name = wc_sanitize_taxonomy_name ( str_replace ( 'pa_' , '' , $term [ 'domain' ] ) );
2018-03-13 11:11:11 +00:00
// Create the taxonomy.
if ( ! in_array ( $attribute_name , wc_get_attribute_taxonomies (), true ) ) {
2018-03-05 18:59:17 +00:00
wc_create_attribute (
array (
'name' => $attribute_name ,
'slug' => $attribute_name ,
'type' => 'select' ,
'order_by' => 'menu_order' ,
'has_archives' => false ,
)
);
2013-07-24 16:01:36 +00:00
}
2017-05-17 10:24:27 +00:00
// Register the taxonomy now so that the import works!
register_taxonomy (
$term [ 'domain' ],
apply_filters ( 'woocommerce_taxonomy_objects_' . $term [ 'domain' ], array ( 'product' ) ),
2018-03-05 18:59:17 +00:00
apply_filters (
'woocommerce_taxonomy_args_' . $term [ 'domain' ], array (
'hierarchical' => true ,
'show_ui' => false ,
'query_var' => true ,
'rewrite' => false ,
)
)
2017-05-17 10:24:27 +00:00
);
2013-07-24 16:01:36 +00:00
}
}
}
}
}
}
}
2017-05-17 21:34:49 +00:00
/**
* Ajax callback for importing one batch of products from a CSV .
*/
public function do_ajax_product_import () {
2017-06-14 15:38:07 +00:00
global $wpdb ;
2017-05-17 21:34:49 +00:00
check_ajax_referer ( 'wc-product-import' , 'security' );
2018-04-04 13:06:13 +00:00
if ( ! $this -> import_allowed () || ! isset ( $_POST [ 'file' ] ) ) { // PHPCS: input var ok.
wp_send_json_error ( array ( 'message' => __ ( 'Insufficient privileges to import products.' , 'woocommerce' ) ) );
2017-05-17 21:34:49 +00:00
}
2018-03-05 18:59:17 +00:00
include_once WC_ABSPATH . 'includes/admin/importers/class-wc-product-csv-importer-controller.php' ;
include_once WC_ABSPATH . 'includes/import/class-wc-product-csv-importer.php' ;
2017-05-17 21:34:49 +00:00
2018-03-13 11:11:11 +00:00
$file = wc_clean ( wp_unslash ( $_POST [ 'file' ] ) ); // PHPCS: input var ok.
2017-05-17 21:34:49 +00:00
$params = array (
2018-03-13 11:11:11 +00:00
'delimiter' => ! empty ( $_POST [ 'delimiter' ] ) ? wc_clean ( wp_unslash ( $_POST [ 'delimiter' ] ) ) : ',' , // PHPCS: input var ok.
'start_pos' => isset ( $_POST [ 'position' ] ) ? absint ( $_POST [ 'position' ] ) : 0 , // PHPCS: input var ok.
'mapping' => isset ( $_POST [ 'mapping' ] ) ? ( array ) wc_clean ( wp_unslash ( $_POST [ 'mapping' ] ) ) : array (), // PHPCS: input var ok.
'update_existing' => isset ( $_POST [ 'update_existing' ] ) ? ( bool ) $_POST [ 'update_existing' ] : false , // PHPCS: input var ok.
2017-06-27 13:39:18 +00:00
'lines' => apply_filters ( 'woocommerce_product_import_batch_size' , 30 ),
2017-05-25 15:41:11 +00:00
'parse' => true ,
2017-05-17 21:34:49 +00:00
);
2017-05-23 14:05:32 +00:00
// Log failures.
if ( 0 !== $params [ 'start_pos' ] ) {
$error_log = array_filter ( ( array ) get_user_option ( 'product_import_error_log' ) );
} else {
$error_log = array ();
}
$importer = WC_Product_CSV_Importer_Controller :: get_importer ( $file , $params );
$results = $importer -> import ();
2017-05-18 17:05:31 +00:00
$percent_complete = $importer -> get_percent_complete ();
2017-05-23 14:05:32 +00:00
$error_log = array_merge ( $error_log , $results [ 'failed' ], $results [ 'skipped' ] );
update_user_option ( get_current_user_id (), 'product_import_error_log' , $error_log );
2017-05-17 21:34:49 +00:00
2017-05-23 14:05:32 +00:00
if ( 100 === $percent_complete ) {
2017-06-14 15:38:07 +00:00
// Clear temp meta.
2018-03-13 11:11:11 +00:00
$wpdb -> delete ( $wpdb -> postmeta , array ( 'meta_key' => '_original_id' ) ); // @codingStandardsIgnoreLine.
2018-03-05 18:59:17 +00:00
$wpdb -> query (
" DELETE { $wpdb -> posts } , { $wpdb -> postmeta } , { $wpdb -> term_relationships }
2017-07-14 10:38:49 +00:00
FROM { $wpdb -> posts }
LEFT JOIN { $wpdb -> term_relationships } ON ( { $wpdb -> posts } . ID = { $wpdb -> term_relationships } . object_id )
LEFT JOIN { $wpdb -> postmeta } ON ( { $wpdb -> posts } . ID = { $wpdb -> postmeta } . post_id )
LEFT JOIN { $wpdb -> term_taxonomy } ON ( { $wpdb -> term_taxonomy } . term_taxonomy_id = { $wpdb -> term_relationships } . term_taxonomy_id )
LEFT JOIN { $wpdb -> terms } ON ( { $wpdb -> terms } . term_id = { $wpdb -> term_taxonomy } . term_id )
WHERE { $wpdb -> posts } . post_type IN ( 'product' , 'product_variation' )
2018-03-05 18:59:17 +00:00
AND { $wpdb -> posts } . post_status = 'importing' "
);
2017-06-14 15:38:07 +00:00
2018-03-13 11:14:24 +00:00
// Clear orphan variations.
$wpdb -> query (
" DELETE products
FROM { $wpdb -> posts } products
LEFT JOIN { $wpdb -> posts } wp ON wp . ID = products . post_parent
WHERE wp . ID IS NULL AND products . post_type = 'product_variation' ; "
);
2017-06-14 15:38:07 +00:00
// Send success.
2018-03-05 18:59:17 +00:00
wp_send_json_success (
array (
'position' => 'done' ,
'percentage' => 100 ,
'url' => add_query_arg ( array ( 'nonce' => wp_create_nonce ( 'product-csv' ) ), admin_url ( 'edit.php?post_type=product&page=product_importer&step=done' ) ),
'imported' => count ( $results [ 'imported' ] ),
'failed' => count ( $results [ 'failed' ] ),
'updated' => count ( $results [ 'updated' ] ),
'skipped' => count ( $results [ 'skipped' ] ),
)
);
2017-05-17 21:34:49 +00:00
} else {
2018-03-05 18:59:17 +00:00
wp_send_json_success (
array (
'position' => $importer -> get_file_position (),
'percentage' => $percent_complete ,
'imported' => count ( $results [ 'imported' ] ),
'failed' => count ( $results [ 'failed' ] ),
'updated' => count ( $results [ 'updated' ] ),
'skipped' => count ( $results [ 'skipped' ] ),
)
);
2017-05-17 21:34:49 +00:00
}
}
2013-07-24 16:01:36 +00:00
}
2017-05-17 10:24:27 +00:00
new WC_Admin_Importers ();