Merge pull request #15116 from woocommerce/refactor/export-import-unification

Made exporter and importer screens, classes and directories consistent
This commit is contained in:
Claudiu Lodromanean 2017-05-17 08:55:44 -07:00 committed by GitHub
commit 72d41a21ca
21 changed files with 741 additions and 553 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5421,118 +5421,188 @@ table.bar_chart {
}
}
.woocommerce-exporter {
background: #fff;
padding: 24px;
margin: 16px 0 16px;
box-shadow: 0 1px 3px rgba(0,0,0,.13);
color: #555;
.woocommerce-progress-form-wrapper,
.woocommerce-exporter-wrapper {
text-align: center;
max-width: 700px;
margin: 40px auto;
header {
border-bottom: 1px solid #eee;
padding: 0 24px;
margin: 0 -24px 24px;
}
h2 {
margin: 0 0 24px;
color: #555;
font-size: 24px;
font-weight: normal;
line-height: 1em;
}
p {
font-size: 1em;
line-height: 1.75em;
font-size: 16px;
color: #555;
margin: 0 0 24px;
}
.form-row {
margin-top: 24px;
}
.spinner {
display: none;
}
.woocommerce-exporter-options th {
width: 320px;
}
.woocommerce-exporter-options th, .woocommerce-exporter-options td {
vertical-align: middle;
label {
font-weight: normal;
color: #555;
.wc-progress-steps {
padding: 0 0 24px;
margin: 0;
list-style: none outside;
overflow: hidden;
color: #ccc;
width:100%;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
li {
width: 25%;
float: left;
padding: 0 0 0.8em;
margin: 0;
text-align: center;
position: relative;
border-bottom: 4px solid #ccc;
line-height: 1.4em;
}
li::before {
content: '';
border: 4px solid #ccc;
border-radius: 100%;
width: 4px;
height: 4px;
position: absolute;
bottom: 0;
left: 50%;
margin-left: -6px;
margin-bottom: -8px;
background: #fff;
}
li.active {
border-color: #a16696;
color: #a16696;
&::before {
border-color: #a16696;
}
}
li.done {
border-color: #a16696;
color: #a16696;
&::before {
border-color: #a16696;
background: #a16696;
}
}
}
.woocommerce-exporter-button {
font-size: 1.25em;
padding: 0.5em 1em !important;
line-height: 1.5em !important;
margin-right: 0.5em;
margin-bottom: 2px;
height: auto !important;
border-radius: 4px;
background-color: #bb77ae;
border-color: #a36597;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 0 #a36597;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 0 #a36597;
text-shadow: 0 -1px 1px #a36597, 1px 0 1px #a36597, 0 1px 1px #a36597, -1px 0 1px #a36597;
margin: 0;
opacity: 1;
&:hover, &:focus, &:active {
background: #a36597;
.wc-actions {
overflow: hidden;
padding: 0 0 2px;
margin: 0 0 24px;
.button {
float: right;
font-size: 1.25em;
padding: 0.5em 1em !important;
line-height: 1.5em !important;
margin-right: 0.5em;
margin-bottom: 2px;
height: auto !important;
border-radius: 4px;
background-color: #bb77ae;
border-color: #a36597;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 0 #a36597;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 0 #a36597;
text-shadow: 0 -1px 1px #a36597, 1px 0 1px #a36597, 0 1px 1px #a36597, -1px 0 1px #a36597;
margin: 0;
opacity: 1;
&:hover, &:focus, &:active {
background: #a36597;
border-color: #a36597;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 0 #a36597;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 0 #a36597;
}
}
}
progress {
width: 100%;
height: 42px;
margin: 24px auto 0;
display: block;
-webkit-appearance: none;
border: none;
display: none;
}
.woocommerce-exporter,
.wc-progress-form-content {
background: #fff;
overflow: hidden;
padding: 24px 24px 0;
margin: 0 0 16px;
box-shadow: 0 1px 3px rgba(0,0,0,.13);
color: #555;
text-align: left;
/* All good till now. Now we'll style the background */
progress::-webkit-progress-bar {
background: #f5f5f5;
border: 2px solid #eee;
border-radius: 4px;
padding: 0;
box-shadow: 0 1px 0px 0 rgba(255, 255, 255, 0.2);
}
header {
border-bottom: 1px solid #eee;
padding: 0;
margin: 0;
}
/* Now the value part */
progress::-webkit-progress-value {
border-radius: 3px;
box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.4);
background:
-webkit-linear-gradient(top, rgba(255, 255, 255, 0.25), rgba(0, 0, 0, 0.2)),
#A46497;
transition: width 1s ease;
}
h2 {
margin: 0 0 24px;
color: #555;
font-size: 24px;
font-weight: normal;
line-height: 1em;
}
p {
font-size: 1em;
line-height: 1.75em;
font-size: 16px;
color: #555;
margin: 0 0 24px;
}
.form-row {
margin-top: 24px;
}
&.woocommerce-exporter__exporting {
.spinner {
display: block;
}
progress {
display: block;
}
.form-row-submit, .woocommerce-exporter-options {
display: none;
}
.woocommerce-exporter-options th,
.woocommerce-importer-options th {
width: 30%;
}
.woocommerce-exporter-options th,
.woocommerce-exporter-options td {
vertical-align: top;
label {
color: #555;
font-weight: normal;
}
}
progress {
width: 100%;
height: 42px;
margin: 24px auto 24px;
display: block;
-webkit-appearance: none;
border: none;
display: none;
}
/* All good till now. Now we'll style the background */
progress::-webkit-progress-bar {
background: #f5f5f5;
border: 2px solid #eee;
border-radius: 4px;
padding: 0;
box-shadow: 0 1px 0px 0 rgba(255, 255, 255, 0.2);
}
/* Now the value part */
progress::-webkit-progress-value {
border-radius: 3px;
box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.4);
background:
-webkit-linear-gradient(top, rgba(255, 255, 255, 0.25), rgba(0, 0, 0, 0.2)),
#A46497;
transition: width 1s ease;
}
&.woocommerce-exporter__exporting,
&.woocommerce-importer__importing {
.spinner {
display: block;
}
progress {
display: block;
}
.wc-actions,
.woocommerce-exporter-options {
display: none;
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,18 @@ jQuery( function ( $ ) {
$title_action.hide();
}
// Progress indicators when showing steps.
$( '.woocommerce-progress-form-wrapper .button-next' ).on( 'click', function() {
$('.wc-progress-form-content').block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
return true;
} );
// Field validation error tips
$( document.body )

File diff suppressed because one or more lines are too long

View File

@ -1,49 +1,69 @@
<?php
/**
* Handles the product CSV exporter UI in admin.
* Init WooCommerce data exporters.
*
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 3.1.0
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
* @version 3.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Admin_Product_Export Class.
* WC_Admin_Exporters Class.
*/
class WC_Admin_Product_Export {
class WC_Admin_Exporters {
/**
* Array of exporter IDs.
*
* @var string[]
*/
protected $exporters = array();
/**
* Constructor.
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
add_action( 'admin_head', array( $this, 'admin_menu_hide' ) );
add_action( 'admin_menu', array( $this, 'add_to_menus' ) );
add_action( 'admin_head', array( $this, 'hide_from_menus' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
add_action( 'admin_init', array( $this, 'download_export_file' ) );
add_action( 'wp_ajax_woocommerce_do_ajax_product_export', array( $this, 'do_ajax_product_export' ) );
// Register WooCommerce exporters.
$this->exporters['product_exporter'] = array(
'menu' => 'edit.php?post_type=product',
'name' => __( 'Product Export', 'woocommerce' ),
'capability' => 'edit_products',
'callback' => array( $this, 'product_exporter' ),
);
}
/**
* Add menu items.
* Add menu items for our custom exporters.
*/
public function admin_menu() {
add_submenu_page( 'edit.php?post_type=product', __( 'Product Export', 'woocommerce' ), __( 'Export', 'woocommerce' ), 'edit_products', 'product_exporter', array( $this, 'admin_screen' ) );
public function add_to_menus() {
foreach ( $this->exporters as $id => $exporter ) {
add_submenu_page( $exporter['menu'], $exporter['name'], $exporter['name'], $exporter['capability'], $id, $exporter['callback'] );
}
}
/**
* Hide menu item from view.
* Hide menu items from view so the pages exist, but the menu items do not.
*/
public function admin_menu_hide() {
public function hide_from_menus() {
global $submenu;
if ( isset( $submenu['edit.php?post_type=product'] ) ) {
foreach ( $submenu['edit.php?post_type=product'] as $key => $menu ) {
if ( 'product_exporter' === $menu[2] ) {
unset( $submenu['edit.php?post_type=product'][ $key ] );
foreach ( $this->exporters as $id => $exporter ) {
if ( isset( $submenu[ $exporter['menu'] ] ) ) {
foreach ( $submenu[ $exporter['menu'] ] as $key => $menu ) {
if ( $id === $menu[2] ) {
unset( $submenu[ $exporter['menu'] ][ $key ] );
}
}
}
}
@ -63,7 +83,7 @@ class WC_Admin_Product_Export {
/**
* Export page UI.
*/
public function admin_screen() {
public function product_exporter() {
include_once( WC_ABSPATH . 'includes/export/class-wc-product-csv-exporter.php' );
include_once( dirname( __FILE__ ) . '/views/html-admin-page-product-export.php' );
}
@ -129,4 +149,4 @@ class WC_Admin_Product_Export {
}
}
new WC_Admin_Product_Export();
new WC_Admin_Exporters();

View File

@ -1,65 +1,104 @@
<?php
/**
* Setup importers for WC data
* Init WooCommerce data importers.
*
* @author WooThemes
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 2.5.0
* @version 3.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'WC_Admin_Importers', false ) ) :
/**
* WC_Admin_Importers Class.
*/
class WC_Admin_Importers {
/**
* Hook in tabs.
* Array of importer IDs.
*
* @var string[]
*/
protected $importers = array();
/**
* Constructor.
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'add_to_menus' ) );
add_action( 'admin_init', array( $this, 'register_importers' ) );
add_action( 'import_start', array( $this, 'post_importer_compatibility' ) );
add_action( 'admin_head', array( $this, 'hide_from_menus' ) );
// Register WooCommerce importers.
$this->importers['product_importer'] = array(
'menu' => 'edit.php?post_type=product',
'name' => __( 'Product Import', 'woocommerce' ),
'capability' => 'edit_products',
'callback' => array( $this, 'product_importer' ),
);
}
/**
* Add menu items.
* Add menu items for our custom importers.
*/
public function register_importers() {
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' ) );
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' ) );
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'] );
}
}
/**
* Add product importer menu item.
* Hide menu items from view so the pages exist, but the menu items do not.
*/
public function product_importer() {
// Load Importer API
require_once ABSPATH . 'wp-admin/includes/import.php';
public function hide_from_menus() {
global $submenu;
if ( ! class_exists( 'WP_Importer' ) ) {
$class_wp_importer = ABSPATH . 'wp-admin/includes/class-wp-importer.php';
if ( file_exists( $class_wp_importer ) ) {
require $class_wp_importer;
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 ] );
}
}
}
}
}
// includes
require( dirname( __FILE__ ) . '/importers/class-wc-product-wp-importer.php' );
/**
* 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.
*/
public function product_importer() {
if ( defined( 'WP_LOAD_IMPORTERS' ) ) {
wp_safe_redirect( admin_url( 'edit.php?post_type=product&page=product_importer' ) );
exit;
}
// Dispatch
$importer = new WC_Product_WP_Importer();
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' );
$importer = new WC_Product_CSV_Importer_Controller();
$importer->dispatch();
}
/**
* Add tax rate importer menu item.
* Register WordPress based importers.
*/
public function register_importers() {
if ( defined( 'WP_LOAD_IMPORTERS' ) ) {
add_action( 'import_start', array( $this, 'post_importer_compatibility' ) );
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' ) );
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.
*/
public function tax_rates_importer() {
// Load Importer API
@ -82,7 +121,7 @@ class WC_Admin_Importers {
}
/**
* When running the WP importer, ensure attributes exist.
* When running the WP XML importer, ensure attributes exist.
*
* 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.
@ -99,44 +138,38 @@ class WC_Admin_Importers {
$parser = new WXR_Parser();
$import_data = $parser->parse( $file );
if ( isset( $import_data['posts'] ) ) {
$posts = $import_data['posts'];
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'] ) );
if ( $posts && sizeof( $posts ) > 0 ) {
foreach ( $posts as $post ) {
if ( 'product' === $post['post_type'] ) {
if ( ! 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'] ) );
// Create the taxonomy
if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies() ) ) {
$attribute = array(
'attribute_label' => $attribute_name,
'attribute_name' => $attribute_name,
'attribute_type' => 'select',
'attribute_orderby' => 'menu_order',
'attribute_public' => 0,
);
$wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute );
delete_transient( 'wc_attribute_taxonomies' );
}
// Register the taxonomy now so that the import works!
register_taxonomy(
$term['domain'],
apply_filters( 'woocommerce_taxonomy_objects_' . $term['domain'], array( 'product' ) ),
apply_filters( 'woocommerce_taxonomy_args_' . $term['domain'], array(
'hierarchical' => true,
'show_ui' => false,
'query_var' => true,
'rewrite' => false,
) )
);
}
// Create the taxonomy
if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies() ) ) {
$attribute = array(
'attribute_label' => $attribute_name,
'attribute_name' => $attribute_name,
'attribute_type' => 'select',
'attribute_orderby' => 'menu_order',
'attribute_public' => 0,
);
$wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute );
delete_transient( 'wc_attribute_taxonomies' );
}
// Register the taxonomy now so that the import works!
register_taxonomy(
$term['domain'],
apply_filters( 'woocommerce_taxonomy_objects_' . $term['domain'], array( 'product' ) ),
apply_filters( 'woocommerce_taxonomy_args_' . $term['domain'], array(
'hierarchical' => true,
'show_ui' => false,
'query_var' => true,
'rewrite' => false,
) )
);
}
}
}
@ -146,6 +179,4 @@ class WC_Admin_Importers {
}
}
endif;
return new WC_Admin_Importers();
new WC_Admin_Importers();

View File

@ -1,57 +0,0 @@
<?php
/**
* Handles the product CSV importer UI in admin.
*
* @author Automattic
* @category Admin
* @package WooCommerce/Admin
* @version 3.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Admin_Product_Import Class.
*/
class WC_Admin_Product_Import {
/**
* Constructor.
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
add_action( 'admin_head', array( $this, 'admin_menu_hide' ) );
}
/**
* Add menu items.
*/
public function admin_menu() {
add_submenu_page( 'edit.php?post_type=product', __( 'Product Import', 'woocommerce' ), __( 'Import', 'woocommerce' ), 'edit_products', 'product_importer', array( $this, 'admin_screen' ) );
}
/**
* Hide menu item from view.
*/
public function admin_menu_hide() {
global $submenu;
if ( isset( $submenu['edit.php?post_type=product'] ) ) {
foreach ( $submenu['edit.php?post_type=product'] as $key => $menu ) {
if ( 'product_importer' === $menu[2] ) {
unset( $submenu['edit.php?post_type=product'][ $key ] );
}
}
}
}
/**
* Import page UI.
*/
public function admin_screen() {
}
}
new WC_Admin_Product_Import();

View File

@ -54,8 +54,8 @@ class WC_Admin {
include_once( dirname( __FILE__ ) . '/class-wc-admin-api-keys.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-webhooks.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-pointers.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-product-import.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-product-export.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-importers.php' );
include_once( dirname( __FILE__ ) . '/class-wc-admin-exporters.php' );
// Help Tabs
if ( apply_filters( 'woocommerce_enable_admin_help_tab', true ) ) {
@ -70,11 +70,6 @@ class WC_Admin {
break;
}
}
// Importers
if ( defined( 'WP_LOAD_IMPORTERS' ) ) {
include_once( dirname( __FILE__ ) . '/class-wc-admin-importers.php' );
}
}
/**

View File

@ -8,83 +8,179 @@ if ( ! class_exists( 'WP_Importer' ) ) {
}
/**
* Product importer - import products into WooCommerce.
* Product importer controller - handles file upload and forms in admin.
*
* @author Automattic
* @category Admin
* @package WooCommerce/Admin/Importers
* @version 3.1.0
*/
class WC_Product_WP_Importer extends WP_Importer {
class WC_Product_CSV_Importer_Controller {
/**
* The current file id.
*
* @var int
*/
public $id;
/**
* The current file url.
* The path to the current file.
*
* @var string
*/
public $file_url;
protected $file = '';
/**
* The current import page.
* The current import step.
*
* @var string
*/
public $import_page;
protected $step = '';
/**
* The current delimiter.
* Progress steps.
*
* @var array
*/
protected $steps = array();
/**
* Errors.
*
* @var array
*/
protected $errors = array();
/**
* The current delimiter for the file being read.
*
* @var string
*/
public $delimiter;
protected $delimiter = ',';
/**
* Constructor.
*/
public function __construct() {
$this->import_page = 'woocommerce_product_csv';
$this->delimiter = empty( $_REQUEST['delimiter'] ) ? ',' : (string) wc_clean( $_REQUEST['delimiter'] );
$this->steps = array(
'upload' => array(
'name' => __( 'Upload CSV file', 'woocommerce' ),
'view' => array( $this, 'upload_form' ),
'handler' => array( $this, 'upload_form_handler' ),
),
'mapping' => array(
'name' => __( 'Column mapping', 'woocommerce' ),
'view' => array( $this, 'mapping_form' ),
'handler' => '',
),
'import' => array(
'name' => __( 'Import', 'woocommerce' ),
'view' => array( $this, 'import' ),
'handler' => '',
),
'done' => array(
'name' => __( 'Done!', 'woocommerce' ),
'view' => array( $this, 'done' ),
'handler' => '',
),
);
$this->step = isset( $_REQUEST['step'] ) ? sanitize_key( $_REQUEST['step'] ) : current( array_keys( $this->steps ) );
$this->file = isset( $_REQUEST['file'] ) ? wc_clean( $_REQUEST['file'] ) : '';
}
/**
* Registered callback function for the WordPress Importer.
* Get the URL for the next step's screen.
* @param string step slug (default: current step)
* @return string URL for next step if a next step exists.
* Admin URL if it's the last step.
* Empty string on failure.
*/
public function get_next_step_link( $step = '' ) {
if ( ! $step ) {
$step = $this->step;
}
$keys = array_keys( $this->steps );
if ( end( $keys ) === $step ) {
return admin_url();
}
$step_index = array_search( $step, $keys );
if ( false === $step_index ) {
return '';
}
$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 &amp; breaking redirects.
);
return add_query_arg( $params );
}
/**
* Output header view.
*/
protected function output_header() {
include( dirname( __FILE__ ) . '/views/html-csv-import-header.php' );
}
/**
* Output steps view.
*/
protected function output_steps() {
include( dirname( __FILE__ ) . '/views/html-csv-import-steps.php' );
}
/**
* Output footer view.
*/
protected function output_footer() {
include( dirname( __FILE__ ) . '/views/html-csv-import-footer.php' );
}
/**
* Get importer instance.
*
* Manages the three separate stages of the CSV import process.
* @param string $file File to import.
* @param array $args Importer arguments.
* @return WC_Product_CSV_Importer
*/
protected function get_importer( $file, $args = array() ) {
$importer_class = apply_filters( 'woocommerce_product_csv_importer_class', 'WC_Product_CSV_Importer' );
return new $importer_class( $file, $args );
}
/**
* Add error message.
*/
protected function add_error( $error ) {
$this->errors[] = $error;
}
/**
* Add error message.
*/
protected function output_errors() {
if ( $this->errors ) {
foreach ( $this->errors as $error ) {
echo '<p class="error inline">' . esc_html( $error ) . '</p>';
}
}
}
/**
* Dispatch current step and show correct view.
*/
public function dispatch() {
include_once( WC_ABSPATH . 'includes/import/class-wc-product-csv-importer.php' );
$this->header();
$step = empty( $_GET['step'] ) ? 0 : (int) $_GET['step'];
switch ( $step ) {
case 0:
$this->greet();
break;
case 1 :
check_admin_referer( 'import-upload' );
if ( $this->handle_upload() ) {
if ( $this->id ) {
$file = get_attached_file( $this->id );
} else {
$file = ABSPATH . $this->file_url;
}
$this->importer_mapping( $file );
}
break;
if ( ! empty( $_POST['save_step'] ) && isset( $this->steps[ $this->step ]['handler'] ) ) {
call_user_func( $this->steps[ $this->step ]['handler'], $this );
}
$this->output_header();
$this->output_steps();
$this->output_errors();
call_user_func( $this->steps[ $this->step ]['view'], $this );
$this->output_footer();
/*switch ( $this->step ) {
case 2 :
check_admin_referer( 'woocommerce-csv-importer' );
$file = null;
@ -100,43 +196,124 @@ class WC_Product_WP_Importer extends WP_Importer {
$this->import( $file );
break;
}
$this->footer();
}*/
}
/**
* Import is starting.
* Output information about the uploading process.
*/
private function import_start() {
if ( function_exists( 'gc_enable' ) ) {
gc_enable();
protected function upload_form() {
$bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
$size = size_format( $bytes );
$upload_dir = wp_upload_dir();
include( dirname( __FILE__ ) . '/views/html-product-csv-import-form.php' );
}
/**
* Handle the upload form and store options.
*/
public function upload_form_handler() {
check_admin_referer( 'woocommerce-csv-importer' );
$file = $this->handle_upload();
if ( is_wp_error( $file ) ) {
$this->add_error( $file->get_message() );
return;
} else {
$this->file = $file;
}
wc_set_time_limit( 0 );
@ob_flush();
@flush();
@ini_set( 'auto_detect_line_endings', '1' );
wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
exit;
}
/**
* Handles the CSV upload and initial parsing of the file to prepare for.
* displaying author import options.
*
* @return string|WP_Error
*/
public function handle_upload() {
if ( empty( $_POST['file_url'] ) ) {
if ( ! isset( $_FILES['import'] ) ) {
return new WP_Error( __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.', 'woocommerce' ) );
}
$overrides = array( 'test_form' => false, 'test_type' => false );
$_FILES['import']['name'] .= '.txt';
$upload = wp_handle_upload( $_FILES['import'], $overrides );
if ( isset( $upload['error'] ) ) {
return new WP_Error( $upload['error'] );
}
// Construct the object array
$object = array(
'post_title' => basename( $upload['file'] ),
'post_content' => $upload['url'],
'post_mime_type' => $upload['type'],
'guid' => $upload['url'],
'context' => 'import',
'post_status' => 'private',
);
// Save the data
$id = wp_insert_attachment( $object, $upload['file'] );
/*
* Schedule a cleanup for one day from now in case of failed
* import or missing wp_import_cleanup() call.
*/
wp_schedule_single_event( time() + DAY_IN_SECONDS, 'importer_scheduled_cleanup', array( $id ) );
return $upload['file'];
} elseif ( file_exists( ABSPATH . $_POST['file_url'] ) ) {
return ABSPATH . $_POST['file_url'];
}
return new WP_Error( __( 'Please upload or provide the link to a valid CSV file.', 'woocommerce' ) );
}
/**
* Mapping step @todo
*/
protected function mapping_form() {
$importer = $this->get_importer( $this->file, array( 'lines' => 1 ) );
$headers = $importer->get_raw_keys();
$sample = current( $importer->get_raw_data() );
if ( empty( $sample ) ) {
$this->add_error( __( 'The file is empty, please try again with a new file.', 'woocommerce' ) );
return;
}
// Check if all fields matches.
if ( 0 === count( array_diff( $headers, $this->get_default_fields() ) ) ) {
wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
exit;
}
include_once( dirname( __FILE__ ) . '/views/html-csv-import-mapping.php' );
}
/**
* Import the file if it exists and is valid.
*
* @param mixed $file
*/
public function import( $file ) {
if ( ! is_file( $file ) ) {
$this->import_error( __( 'The file does not exist, please try again.', 'woocommerce' ) );
public function import() {
if ( ! is_file( $this->file ) ) {
$this->add_error( __( 'The file does not exist, please try again.', 'woocommerce' ) );
return;
}
$this->import_start();
$args = array( 'parse' => true );
if ( ! empty( $_POST['map_to'] ) ) {
$args['mapping'] = wp_unslash( $_POST['map_to'] );
}
$importer = $this->get_importer( $file, $args );
$importer = $this->get_importer( $this->file, $args );
$data = $importer->import();
$imported = count( $data['imported'] );
$failed = count( $data['failed'] );
@ -161,134 +338,13 @@ class WC_Product_WP_Importer extends WP_Importer {
/* translators: %d: import results */
printf( __( 'Import complete: %s', 'woocommerce' ), $results );
echo '</p></div>';
$this->import_end();
}
/**
* Performs post-import cleanup of files and the cache.
* @todo
*/
public function import_end() {
echo '<p>' . __( 'All done!', 'woocommerce' ) . ' <a href="' . admin_url( 'edit.php?post_type=product' ) . '">' . __( 'View products', 'woocommerce' ) . '</a>' . '</p>';
protected function done() {
do_action( 'import_end' );
}
/**
* Handles the CSV upload and initial parsing of the file to prepare for.
* displaying author import options.
*
* @return bool False if error uploading or invalid file, true otherwise
*/
public function handle_upload() {
if ( empty( $_POST['file_url'] ) ) {
$file = wp_import_handle_upload();
if ( isset( $file['error'] ) ) {
$this->import_error( $file['error'] );
}
$this->id = absint( $file['id'] );
} elseif ( file_exists( ABSPATH . $_POST['file_url'] ) ) {
$this->file_url = esc_attr( $_POST['file_url'] );
} else {
$this->import_error();
}
return true;
}
/**
* Output header html.
*/
public function header() {
echo '<div class="wrap">';
echo '<h1>' . __( 'Import products', 'woocommerce' ) . '</h1>';
}
/**
* Output footer html.
*/
public function footer() {
echo '</div>';
}
/**
* Output information about the uploading process.
*/
public function greet() {
echo '<div class="narrow">';
echo '<p>' . __( 'Hi there! Upload a CSV file containing products to import them into your shop. Choose a .csv file to upload, then click "Upload file and import".', 'woocommerce' ) . '</p>';
$action = 'admin.php?import=woocommerce_product_csv&step=1';
$bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
$size = size_format( $bytes );
$upload_dir = wp_upload_dir();
if ( ! empty( $upload_dir['error'] ) ) :
?><div class="error"><p><?php _e( 'Before you can upload your import file, you will need to fix the following error:', 'woocommerce' ); ?></p>
<p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
else :
?>
<form enctype="multipart/form-data" id="import-upload-form" method="post" action="<?php echo esc_attr( wp_nonce_url( $action, 'import-upload' ) ); ?>">
<table class="form-table">
<tbody>
<tr>
<th>
<label for="upload"><?php _e( 'Choose a file from your computer:', 'woocommerce' ); ?></label>
</th>
<td>
<input type="file" id="upload" name="import" size="25" />
<input type="hidden" name="action" value="save" />
<input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
<small><?php
/* translators: %s: maximum upload size */
printf(
__( 'Maximum size: %s', 'woocommerce' ),
$size
);
?></small>
</td>
</tr>
<tr>
<th>
<label for="file_url"><?php _e( 'OR enter path to file:', 'woocommerce' ); ?></label>
</th>
<td>
<?php echo ' ' . ABSPATH . ' '; ?><input type="text" id="file_url" name="file_url" size="25" />
</td>
</tr>
<tr>
<th><label><?php _e( 'Delimiter', 'woocommerce' ); ?></label><br/></th>
<td><input type="text" name="delimiter" placeholder="," size="2" /></td>
</tr>
</tbody>
</table>
<p class="submit">
<input type="submit" class="button" value="<?php esc_attr_e( 'Upload file and import', 'woocommerce' ); ?>" />
</p>
</form>
<?php
endif;
echo '</div>';
}
/**
* Show import error and quit.
* @param string $message
*/
private function import_error( $message = '' ) {
echo '<p><strong>' . __( 'Sorry, there has been an error.', 'woocommerce' ) . '</strong><br />';
if ( $message ) {
echo esc_html( $message );
}
echo '</p>';
$this->footer();
die();
}
/**
@ -402,47 +458,4 @@ class WC_Product_WP_Importer extends WP_Importer {
return apply_filters( 'woocommerce_csv_product_import_mapping_options', $options, $item );
}
/**
* CSV mapping.
*
* @param string $file File path.
*/
protected function importer_mapping( $file ) {
$importer = $this->get_importer( $file, array( 'lines' => 1 ) );
$headers = $importer->get_raw_keys();
$sample = current( $importer->get_raw_data() );
if ( empty( $sample ) ) {
$this->import_error( __( 'The file is empty, please try again with a new file.', 'woocommerce' ) );
}
// Check if all fields matches.
if ( 0 === count( array_diff( $headers, $this->get_default_fields() ) ) ) {
$params = array(
'import' => $this->import_page,
'step' => 2,
'file_id' => $this->id,
'file_url' => $this->file_url,
'delimiter' => $this->delimiter,
'_wpnonce' => wp_create_nonce( 'woocommerce-csv-importer' ), // wp_nonce_url() escapes & to &amp; breaking redirects.
);
wp_redirect( add_query_arg( $params, admin_url( 'admin.php' ) ) );
}
include_once( dirname( __FILE__ ) . '/views/html-csv-mapping.php' );
}
/**
* Get importer instance.
*
* @param string $file File to import.
* @param array $args Importer arguments.
* @return WC_Product_CSV_Importer
*/
protected function get_importer( $file, $args = array() ) {
$importer_class = apply_filters( 'woocommerce_product_csv_impoter_class', 'WC_Product_CSV_Importer' );
return new $importer_class( $file, $args );
}
}

View File

@ -0,0 +1,10 @@
<?php
/**
* Admin View: Header
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
</div>
</div>

View File

@ -0,0 +1,12 @@
<?php
/**
* Admin View: Header
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<div class="wrap woocommerce">
<h1><?php esc_html_e( 'Import Products', 'woocommerce' ); ?></h1>
<div class="woocommerce-progress-form-wrapper">

View File

@ -1,23 +1,16 @@
<?php
/**
* Admin View: Importer - CSV mapping
*
* @var array $headers CSV headers.
* @var array $sample CSV sample.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<form action="<?php echo esc_url( admin_url( 'admin.php?import=' . $this->import_page . '&step=2' ) ); ?>" method="post">
<h2 class="title"><?php esc_html_e( 'Fields to map', 'woocommerce' ); ?></h2>
<p><?php esc_html_e( 'Select fields from your CSV file to map against products fields.', 'woocommerce' ); ?></p>
<?php wp_nonce_field( 'woocommerce-csv-importer' ); ?>
<input type="hidden" name="file_id" value="<?php echo esc_attr( $this->id ); ?>" />
<input type="hidden" name="file_url" value="<?php echo esc_attr( $this->file_url ); ?>" />
<input type="hidden" name="delimiter" value="<?php echo esc_attr( $this->delimiter ); ?>" />
<form class="wc-progress-form-content woocommerce-importer" method="post" action="<?php echo esc_url( $this->get_next_step_link() ) ?>">
<header>
<h2><?php esc_html_e( 'Map CSV fields to products', 'woocommerce' ); ?></h2>
<p><?php esc_html_e( 'Select fields from your CSV file to map against products fields, or to ignore during import.', 'woocommerce' ); ?></p>
</header>
<table class="widefat wc-importer__mapping--table">
<thead>
@ -53,6 +46,10 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php endforeach; ?>
</tbody>
</table>
<?php submit_button( __( 'Submit', 'woocommerce' ), 'secondary' ); ?>
<div class="wc-actions">
<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="delimiter" value="<?php echo esc_attr( $this->delimiter ); ?>" />
<?php wp_nonce_field( 'woocommerce-csv-importer' ); ?>
</div>
</form>

View File

@ -0,0 +1,19 @@
<?php
/**
* Admin View: Steps
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<ol class="wc-progress-steps">
<?php foreach ( $this->steps as $step_key => $step ) : ?>
<li class="<?php
if ( $step_key === $this->step ) {
echo 'active';
} elseif ( array_search( $this->step, array_keys( $this->steps ) ) > array_search( $step_key, array_keys( $this->steps ) ) ) {
echo 'done';
}
?>"><?php echo esc_html( $step['name'] ); ?></li>
<?php endforeach; ?>
</ol>

View File

@ -0,0 +1,63 @@
<?php
/**
* Admin View: Product import form
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<form class="wc-progress-form-content woocommerce-importer" enctype="multipart/form-data" method="post">
<header>
<h2><?php esc_html_e( 'Import products from a CSV file', 'woocommerce' ); ?></h2>
<p><?php esc_html_e( 'This tool allows you to import (or merge) product data to your store from a CSV file.', 'woocommerce' ); ?></p>
</header>
<table class="form-table woocommerce-importer-options">
<tbody>
<tr>
<th scope="row">
<label for="upload">
<?php _e( 'Choose a file from your computer:', 'woocommerce' ); ?>
</label>
</th>
<td>
<?php
if ( ! empty( $upload_dir['error'] ) ) {
?><div class="inline error"><p><?php esc_html_e( 'Before you can upload your import file, you will need to fix the following error:', 'woocommerce' ); ?></p>
<p><strong><?php echo esc_html( $upload_dir['error'] ); ?></strong></p></div><?php
} else {
?>
<input type="file" id="upload" name="import" size="25" />
<input type="hidden" name="action" value="save" />
<input type="hidden" name="max_file_size" value="<?php echo esc_attr( $bytes ); ?>" />
<br><small><?php
/* translators: %s: maximum upload size */
printf(
__( 'Maximum size: %s', 'woocommerce' ),
$size
);
?></small>
<?php
}
?>
</td>
</tr>
<tr>
<th>
<label for="file_url"><?php _e( 'OR enter the path to file on your server:', 'woocommerce' ); ?></label>
</th>
<td>
<code><?php echo esc_html( ABSPATH ) . ' '; ?></code><input type="text" id="file_url" name="file_url" size="25" />
</td>
</tr>
<tr>
<th><label><?php _e( 'CSV Delimiter', 'woocommerce' ); ?></label><br/></th>
<td><input type="text" name="delimiter" placeholder="," size="2" /></td>
</tr>
</tbody>
</table>
<div class="wc-actions">
<input type="submit" class="button button-primary button-next" value="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>" name="save_step" />
<?php wp_nonce_field( 'woocommerce-csv-importer' ); ?>
</div>
</form>

View File

@ -13,62 +13,64 @@ $exporter = new WC_Product_CSV_Exporter();
<div class="wrap woocommerce">
<h1><?php esc_html_e( 'Export Products', 'woocommerce' ); ?></h1>
<form class="woocommerce-exporter">
<header>
<span class="spinner is-active"></span>
<h2><?php esc_html_e( 'Export products to a CSV file', 'woocommerce' ); ?></h2>
<p><?php esc_html_e( 'This tool allows you to generate and download a CSV file containing a list of all products.', 'woocommerce' ); ?></p>
</header>
<div class="woocommerce-exporter-wrapper">
<form class="woocommerce-exporter">
<header>
<span class="spinner is-active"></span>
<h2><?php esc_html_e( 'Export products to a CSV file', 'woocommerce' ); ?></h2>
<p><?php esc_html_e( 'This tool allows you to generate and download a CSV file containing a list of all products.', 'woocommerce' ); ?></p>
</header>
<table class="form-table woocommerce-exporter-options">
<tbody>
<tr>
<th scope="row">
<label for="woocommerce-exporter-types"><?php esc_html_e( 'Which product types should be exported?', 'woocommerce' ); ?></label>
</th>
<td>
<select id="woocommerce-exporter-types" class="woocommerce-exporter-types wc-enhanced-select" style="width:100%;" multiple data-placeholder="<?php esc_attr_e( 'Export all', 'woocommerce' ); ?>">
<?php
foreach ( wc_get_product_types() as $value => $label ) {
echo '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
}
?>
<option value="variation"><?php esc_html_e( 'Product variations', 'woocommerce' ); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for="woocommerce-exporter-columns"><?php esc_html_e( 'What product data should be exported?', 'woocommerce' ); ?></label>
</th>
<td>
<select id="woocommerce-exporter-columns" class="woocommerce-exporter-columns wc-enhanced-select" style="width:100%;" multiple data-placeholder="<?php esc_attr_e( 'Export all data', 'woocommerce' ); ?>">
<?php
foreach ( $exporter->get_default_column_names() as $column_id => $column_name ) {
echo '<option value="' . esc_attr( $column_id ) . '">' . esc_html( $column_name ) . '</option>';
}
?>
<option value="downloads"><?php esc_html_e( 'Downloads', 'woocommerce' ); ?></option>
<option value="attributes"><?php esc_html_e( 'Attributes', 'woocommerce' ); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for="woocommerce-exporter-meta"><?php esc_html_e( 'Export custom meta data?', 'woocommerce' ); ?></label>
</th>
<td>
<input type="checkbox" id="woocommerce-exporter-meta" value="1" />
<label for="woocommerce-exporter-meta"><?php esc_html_e( 'Yes, export all meta data', 'woocommerce' ); ?></label>
</td>
</tr>
</tbody>
</table>
<div class="form-row form-row-submit">
<input type="submit" class="woocommerce-exporter-button button button-primary" value="<?php esc_attr_e( 'Generate CSV', 'woocommerce' ); ?>" />
</div>
<div>
<progress class="woocommerce-exporter-progress" max="100" value="0"></progress>
</div>
</form>
<table class="form-table woocommerce-exporter-options">
<tbody>
<tr>
<th scope="row">
<label for="woocommerce-exporter-types"><?php esc_html_e( 'Which product types should be exported?', 'woocommerce' ); ?></label>
</th>
<td>
<select id="woocommerce-exporter-types" class="woocommerce-exporter-types wc-enhanced-select" style="width:100%;" multiple data-placeholder="<?php esc_attr_e( 'Export all', 'woocommerce' ); ?>">
<?php
foreach ( wc_get_product_types() as $value => $label ) {
echo '<option value="' . esc_attr( $value ) . '">' . esc_html( $label ) . '</option>';
}
?>
<option value="variation"><?php esc_html_e( 'Product variations', 'woocommerce' ); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for="woocommerce-exporter-columns"><?php esc_html_e( 'What product data should be exported?', 'woocommerce' ); ?></label>
</th>
<td>
<select id="woocommerce-exporter-columns" class="woocommerce-exporter-columns wc-enhanced-select" style="width:100%;" multiple data-placeholder="<?php esc_attr_e( 'Export all data', 'woocommerce' ); ?>">
<?php
foreach ( $exporter->get_default_column_names() as $column_id => $column_name ) {
echo '<option value="' . esc_attr( $column_id ) . '">' . esc_html( $column_name ) . '</option>';
}
?>
<option value="downloads"><?php esc_html_e( 'Downloads', 'woocommerce' ); ?></option>
<option value="attributes"><?php esc_html_e( 'Attributes', 'woocommerce' ); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for="woocommerce-exporter-meta"><?php esc_html_e( 'Export custom meta data?', 'woocommerce' ); ?></label>
</th>
<td>
<input type="checkbox" id="woocommerce-exporter-meta" value="1" />
<label for="woocommerce-exporter-meta"><?php esc_html_e( 'Yes, export all meta data', 'woocommerce' ); ?></label>
</td>
</tr>
</tbody>
</table>
<div class="wc-actions">
<input type="submit" class="woocommerce-exporter-button button button-primary" value="<?php esc_attr_e( 'Generate CSV', 'woocommerce' ); ?>" />
</div>
<div>
<progress class="woocommerce-exporter-progress" max="100" value="0"></progress>
</div>
</form>
</div>
</div>

View File

@ -30,6 +30,7 @@ function wc_get_screen_ids() {
'toplevel_page_wc-reports',
'product_page_product_attributes',
'product_page_product_exporter',
'product_page_product_importer',
'edit-product',
'product',
'edit-shop_coupon',