Import Products from any XML or CSV to WooCommerce - Version 1.4.0

Version Description

improvement: notice on plugin activation when WooCoomerce Add-On Pro installed improvement: match cross-sell products by title bug fix: shipping class not imported properly in some cases

Download this release

Release Info

Developer soflyy
Plugin Icon 128x128 Import Products from any XML or CSV to WooCommerce
Version 1.4.0
Comparing to
See all releases

Code changes from version 1.3.9 to 1.4.0

controllers/controller/admin.php CHANGED
@@ -44,14 +44,14 @@ abstract class PMWI_Controller_Admin extends PMWI_Controller {
44
  if ( ! is_a($wp_styles, 'WP_Styles'))
45
  $wp_styles = new WP_Styles();
46
 
47
- wp_enqueue_style('pmwi-admin-style', PMWI_ROOT_URL . '/static/css/admin.css', array(), PMWI_VERSION);
48
 
49
  if ( version_compare(get_bloginfo('version'), '3.8-RC1') >= 0 ){
50
  wp_enqueue_style('pmwi-admin-style-wp-3.8', PMWI_ROOT_URL . '/static/css/admin-wp-3.8.css');
51
  }
52
 
53
  wp_enqueue_script('pmwi-script', PMWI_ROOT_URL . '/static/js/pmwi.js', array('jquery'));
54
- wp_enqueue_script('pmwi-admin-script', PMWI_ROOT_URL . '/static/js/admin.js', array('jquery', 'jquery-ui-core', 'jquery-ui-resizable', 'jquery-ui-dialog', 'jquery-ui-datepicker', 'jquery-ui-draggable', 'jquery-ui-droppable', 'pmxi-admin-script'), PMWI_VERSION);
55
 
56
  global $woocommerce;
57
 
44
  if ( ! is_a($wp_styles, 'WP_Styles'))
45
  $wp_styles = new WP_Styles();
46
 
47
+ wp_enqueue_style('pmwi-admin-style', PMWI_ROOT_URL . '/static/css/admin.css', array(), PMWI_FREE_VERSION);
48
 
49
  if ( version_compare(get_bloginfo('version'), '3.8-RC1') >= 0 ){
50
  wp_enqueue_style('pmwi-admin-style-wp-3.8', PMWI_ROOT_URL . '/static/css/admin-wp-3.8.css');
51
  }
52
 
53
  wp_enqueue_script('pmwi-script', PMWI_ROOT_URL . '/static/js/pmwi.js', array('jquery'));
54
+ wp_enqueue_script('pmwi-admin-script', PMWI_ROOT_URL . '/static/js/admin.js', array('jquery', 'jquery-ui-core', 'jquery-ui-resizable', 'jquery-ui-dialog', 'jquery-ui-datepicker', 'jquery-ui-draggable', 'jquery-ui-droppable', 'pmxi-admin-script'), PMWI_FREE_VERSION);
55
 
56
  global $woocommerce;
57
 
filters/pmxi_save_options.php CHANGED
@@ -1,11 +1,16 @@
1
  <?php
2
- function pmwi_pmxi_save_options($post){
3
- if ($post['update_attributes_logic'] == 'only'){
4
- $post['attributes_list'] = explode(",", $post['attributes_only_list']);
 
 
 
 
 
 
5
  }
6
- elseif ($post['update_attributes_logic'] == 'all_except'){
7
- $post['attributes_list'] = explode(",", $post['attributes_except_list']);
8
  }
9
  return $post;
10
- }
11
- ?>
1
  <?php
2
+ /**
3
+ * Filter import options before saving.
4
+ *
5
+ * @param $post
6
+ * @return mixed
7
+ */
8
+ function pmwi_pmxi_save_options($post) {
9
+ if ($post['update_attributes_logic'] == 'only') {
10
+ $post['attributes_list'] = empty($post['attributes_only_list']) ? array() : explode(",", $post['attributes_only_list']);
11
  }
12
+ elseif ($post['update_attributes_logic'] == 'all_except') {
13
+ $post['attributes_list'] = empty($post['attributes_except_list']) ? array() : explode(",", $post['attributes_except_list']);
14
  }
15
  return $post;
16
+ }
 
models/import/record.php CHANGED
@@ -627,7 +627,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
627
 
628
  public function import( $importData = array() ){
629
 
630
- if ($importData['import']->options['custom_type'] != 'product') return;
631
 
632
  global $wpdb;
633
 
@@ -638,7 +638,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
638
  $this->logger = $importData['logger'];
639
  $this->xpath = $importData['xpath_prefix'];
640
 
641
- $product_taxonomies = array('post_format', 'product_type', 'product_shipping_class');
642
  $this->product_taxonomies = array_diff_key(get_taxonomies_by_object_type(array('product'), 'object'), array_flip($product_taxonomies));
643
 
644
  extract($importData);
@@ -740,7 +740,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
740
 
741
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
742
  {
743
- $p_shipping_class = (int) $t_shipping_class->term_taxonomy_id;
744
  }
745
  else
746
  {
@@ -748,7 +748,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
748
 
749
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
750
  {
751
- $p_shipping_class = (int) $t_shipping_class['term_taxonomy_id'];
752
  }
753
  else
754
  {
@@ -759,7 +759,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
759
 
760
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
761
  {
762
- $p_shipping_class = (int) $t_shipping_class['term_taxonomy_id'];
763
  }
764
  }
765
  }
@@ -775,7 +775,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
775
 
776
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
777
  {
778
- $p_shipping_class = (int) $t_shipping_class['term_taxonomy_id'];
779
  }
780
  else
781
  {
@@ -783,7 +783,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
783
 
784
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
785
  {
786
- $p_shipping_class = (int) $t_shipping_class['term_taxonomy_id'];
787
  }
788
  else
789
  {
@@ -794,7 +794,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
794
 
795
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
796
  {
797
- $p_shipping_class = (int) $t_shipping_class['term_taxonomy_id'];
798
  }
799
  }
800
  }
@@ -1667,6 +1667,10 @@ class PMWI_Import_Record extends PMWI_Model_Record {
1667
  $linked_product = $query[0];
1668
  }
1669
  wp_reset_postdata();
 
 
 
 
1670
  }
1671
  }
1672
 
627
 
628
  public function import( $importData = array() ){
629
 
630
+ if ($importData['import']->options['custom_type'] != 'product') return;
631
 
632
  global $wpdb;
633
 
638
  $this->logger = $importData['logger'];
639
  $this->xpath = $importData['xpath_prefix'];
640
 
641
+ $product_taxonomies = array('post_format', 'product_type', 'product_shipping_class', 'product_visibility');
642
  $this->product_taxonomies = array_diff_key(get_taxonomies_by_object_type(array('product'), 'object'), array_flip($product_taxonomies));
643
 
644
  extract($importData);
740
 
741
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
742
  {
743
+ $p_shipping_class = (int) $t_shipping_class->term_id;
744
  }
745
  else
746
  {
748
 
749
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
750
  {
751
+ $p_shipping_class = (int) $t_shipping_class['term_id'];
752
  }
753
  else
754
  {
759
 
760
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
761
  {
762
+ $p_shipping_class = (int) $t_shipping_class['term_id'];
763
  }
764
  }
765
  }
775
 
776
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
777
  {
778
+ $p_shipping_class = (int) $t_shipping_class['term_id'];
779
  }
780
  else
781
  {
783
 
784
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
785
  {
786
+ $p_shipping_class = (int) $t_shipping_class['term_id'];
787
  }
788
  else
789
  {
794
 
795
  if ( ! empty($t_shipping_class) and ! is_wp_error($t_shipping_class) )
796
  {
797
+ $p_shipping_class = (int) $t_shipping_class['term_id'];
798
  }
799
  }
800
  }
1667
  $linked_product = $query[0];
1668
  }
1669
  wp_reset_postdata();
1670
+ if (!$linked_product) {
1671
+ // Search linked product by title.
1672
+ $linked_product = get_page_by_title( $id, OBJECT, 'product' );
1673
+ }
1674
  }
1675
  }
1676
 
plugin.php CHANGED
@@ -3,734 +3,705 @@
3
  Plugin Name: WP All Import - WooCommerce Add-On
4
  Plugin URI: http://www.wpallimport.com/
5
  Description: An extremely easy, drag & drop importer to import WooCommerce simple products. A paid upgrade is available for premium support and support for Variable, Grouped, and External/Affiliate products
6
- Version: 1.3.9
7
  Author: Soflyy
8
- WC tested up to: 3.4.0
9
  */
10
- /**
11
- * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value
12
- * @var string
13
- */
14
- define('PMWI_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__)));
15
- /**
16
- * Plugin root url for referencing static content
17
- * @var string
18
- */
19
- define('PMWI_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
20
- /**
21
- * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention,
22
- * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which
23
- * names composed using this prefix)
24
- * @var string
25
- */
26
- define('PMWI_PREFIX', 'pmwi_');
27
-
28
- define('PMWI_FREE_VERSION', '1.3.9');
29
-
30
- define('PMWI_EDITION', 'free');
31
-
32
- /**
33
- * Main plugin file, Introduces MVC pattern
34
- *
35
- * @singletone
36
- * @author Maksym Tsypliakov <maksym.tsypliakov@gmail.com>
37
- */
38
-
39
- final class PMWI_Plugin {
40
- /**
41
- * Singletone instance
42
- * @var PMWI_Plugin
43
- */
44
- protected static $instance;
45
-
46
- /**
47
- * Plugin options
48
- * @var array
49
- */
50
- protected $options = array();
51
-
52
- /**
53
- * Plugin root dir
54
- * @var string
55
- */
56
- const ROOT_DIR = PMWI_ROOT_DIR;
57
- /**
58
- * Plugin root URL
59
- * @var string
60
- */
61
- const ROOT_URL = PMWI_ROOT_URL;
62
- /**
63
- * Prefix used for names of shortcodes, action handlers, filter functions etc.
64
- * @var string
65
- */
66
- const PREFIX = PMWI_PREFIX;
67
- /**
68
- * Plugin file path
69
- * @var string
70
- */
71
- const FILE = __FILE__;
72
-
73
- /**
74
- * Return singletone instance
75
- * @return PMWI_Plugin
76
- */
77
- static public function getInstance() {
78
- if (self::$instance == NULL) {
79
- self::$instance = new self();
80
- }
81
- return self::$instance;
82
- }
83
-
84
- /**
85
- * Common logic for requestin plugin info fields
86
- */
87
- public function __call($method, $args) {
88
- if (preg_match('%^get(.+)%i', $method, $mtch)) {
89
- $info = get_plugin_data(self::FILE);
90
- if (isset($info[$mtch[1]])) {
91
- return $info[$mtch[1]];
92
- }
93
- }
94
- throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
95
- }
96
-
97
- /**
98
- * Get path to plagin dir relative to wordpress root
99
- * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
100
- * @return string
101
- */
102
- public function getRelativePath($noForwardSlash = false) {
103
- $wp_root = str_replace('\\', '/', ABSPATH);
104
- return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
105
- }
106
-
107
- /**
108
- * Check whether plugin is activated as network one
109
- * @return bool
110
- */
111
- public function isNetwork() {
112
- if ( !is_multisite() )
113
- return false;
114
-
115
- $plugins = get_site_option('active_sitewide_plugins');
116
- if (isset($plugins[plugin_basename(self::FILE)]))
117
- return true;
118
-
119
- return false;
120
- }
121
-
122
- /**
123
- * Check whether permalinks is enabled
124
- * @return bool
125
- */
126
- public function isPermalinks() {
127
- global $wp_rewrite;
128
-
129
- return $wp_rewrite->using_permalinks();
130
- }
131
-
132
- /**
133
- * Return prefix for plugin database tables
134
- * @return string
135
- */
136
- public function getTablePrefix() {
137
- global $wpdb;
138
- return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
139
- }
140
-
141
- /**
142
- * Return prefix for wordpress database tables
143
- * @return string
144
- */
145
- public function getWPPrefix() {
146
- global $wpdb;
147
- return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix);
148
- }
149
-
150
- /**
151
- * Class constructor containing dispatching logic
152
- * @param string $rootDir Plugin root dir
153
- * @param string $pluginFilePath Plugin main file
154
- */
155
- protected function __construct() {
156
-
157
- // create/update required database tables
158
-
159
- // register autoloading method
160
- spl_autoload_register(array($this, 'autoload'));
161
-
162
- // register helpers
163
- if (is_dir(self::ROOT_DIR . '/helpers')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/helpers/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
164
- require_once $filePath;
165
- }
166
-
167
- // init plugin options
168
- $option_name = get_class($this) . '_Options';
169
- $options_default = PMWI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
170
- $this->options = array_intersect_key(get_option($option_name, array()), $options_default) + $options_default;
171
- $this->options = array_intersect_key($options_default, array_flip(array('info_api_url'))) + $this->options; // make sure hidden options apply upon plugin reactivation
172
-
173
- update_option($option_name, $this->options);
174
- $this->options = get_option(get_class($this) . '_Options');
175
-
176
- register_activation_hook(self::FILE, array($this, 'activation'));
177
-
178
- // register action handlers
179
- if (is_dir(self::ROOT_DIR . '/actions')) if (is_dir(self::ROOT_DIR . '/actions')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/actions/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
180
- require_once $filePath;
181
- $function = $actionName = basename($filePath, '.php');
182
- if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
183
- $actionName = $m[1];
184
- $priority = intval($m[2]);
185
- } else {
186
- $priority = 10;
187
- }
188
- add_action($actionName, self::PREFIX . str_replace('-', '_', $function), $priority, 99); // since we don't know at this point how many parameters each plugin expects, we make sure they will be provided with all of them (it's unlikely any developer will specify more than 99 parameters in a function)
189
- }
190
-
191
- // register filter handlers
192
- if (is_dir(self::ROOT_DIR . '/filters')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/filters/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
193
- require_once $filePath;
194
- $function = $actionName = basename($filePath, '.php');
195
- if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
196
- $actionName = $m[1];
197
- $priority = intval($m[2]);
198
- } else {
199
- $priority = 10;
200
- }
201
- add_filter($actionName, self::PREFIX . str_replace('-', '_', $function), $priority, 99); // since we don't know at this point how many parameters each plugin expects, we make sure they will be provided with all of them (it's unlikely any developer will specify more than 99 parameters in a function)
202
- }
203
-
204
- // register shortcodes handlers
205
- if (is_dir(self::ROOT_DIR . '/shortcodes')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/shortcodes/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
206
- $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath)));
207
- add_shortcode($tag, array($this, 'shortcodeDispatcher'));
208
- }
209
-
210
- // register admin page pre-dispatcher
211
- add_action('admin_init', array($this, 'adminInit'));
212
- add_action('admin_init', array($this, 'migrate_options'));
213
- add_action('init', array($this, 'init'));
214
-
215
- }
216
-
217
- public function migrate_options(){
218
-
219
- $installed_ver = get_option( "wp_all_import_woocommerce_addon_db_version" );
220
-
221
- if ( $installed_ver == PMWI_FREE_VERSION || ! class_exists( 'PMXI_Plugin' ) ) return true;
222
-
223
- $imports = new PMXI_Import_List();
224
-
225
- $templates = new PMXI_Template_List();
226
-
227
- foreach ($imports->setColumns($imports->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $imp){
228
- $imp->getById($imp->id);
229
- if ( ! $imp->isEmpty() ){
230
- $options = $imp->options;
231
- $this->migrate($options, $installed_ver);
232
- $imp->set(array(
233
- 'options' => $options
234
- ))->update();
235
- }
236
- }
237
-
238
- foreach ($templates->setColumns($templates->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $tpl){
239
- $tpl->getById($tpl->id);
240
- if ( ! $tpl->isEmpty() ) {
241
- $options = ( empty($tpl->options) ) ? array() : $tpl->options;
242
- $this->migrate($options, $installed_ver);
243
- $tpl->set(array(
244
- 'options' => $options
245
- ))->update();
246
- }
247
- }
248
- update_option( "wp_all_import_woocommerce_addon_db_version", PMWI_FREE_VERSION );
249
- }
250
-
251
- private function migrate(&$options, $version){
252
-
253
- // Update _featured, _visibility and _stock_status options according to WooCommerce 3.0
254
- if ( version_compare($version, '2.3.7-beta-2.1') < 0 ){
255
-
256
- $remove_cf = array('_featured', '_visibility', '_stock_status');
257
-
258
- if ($options['is_keep_former_posts'] == 'no'
259
- && $options['update_all_data'] == 'no'){
260
-
261
- if ($options['is_update_custom_fields']){
262
- if (in_array($options['update_custom_fields_logic'], array('only', 'all_except'))){
263
- // Update Options
264
- switch ($options['update_custom_fields_logic']){
265
- case 'only':
266
- $fields_list = explode(',', $options['custom_fields_only_list']);
267
- if ( ! in_array('_featured', $fields_list) ){
268
- $options['is_update_featured_status'] = 0;
269
- }
270
- if ( ! in_array('_visibility', $fields_list) ){
271
- $options['is_update_catalog_visibility'] = 0;
272
- }
273
- break;
274
- case 'all_except':
275
- $fields_list = explode(',', $options['custom_fields_except_list']);
276
- if ( in_array('_featured', $fields_list) ){
277
- $options['is_update_featured_status'] = 0;
278
- }
279
- if ( in_array('_visibility', $fields_list) ){
280
- $options['is_update_catalog_visibility'] = 0;
281
- }
282
- break;
283
- }
284
- }
285
- }
286
- else{
287
- $options['is_update_advanced_options'] = 0;
288
- $options['is_update_featured_status'] = 0;
289
- $options['is_update_catalog_visibility'] = 0;
290
- }
291
- }
292
-
293
- // remove deprecated fields from custom fields list
294
- $options_to_update = array('custom_fields_list', 'custom_fields_only_list', 'custom_fields_except_list');
295
- foreach ($options_to_update as $option){
296
- if ( ! empty($options[$option])){
297
- $fields_list = is_array($options[$option]) ? $options[$option] : explode(',', $options[$option]);
298
- foreach ($fields_list as $key => $value){
299
- if (in_array($value, $remove_cf)){
300
- unset($fields_list[$key]);
301
- }
302
- }
303
- $options[$option] = is_array($options[$option]) ? $fields_list : implode(',', $fields_list);
304
- }
305
- }
306
- }
307
- }
308
-
309
- public function init()
310
- {
311
- $this->load_plugin_textdomain();
312
- }
313
-
314
- /**
315
- * Load Localisation files.
316
- *
317
- * Note: the first-loaded translation file overrides any following ones if the same translation is present
318
- *
319
- * @access public
320
- * @return void
321
- */
322
- public function load_plugin_textdomain() {
323
-
324
- $locale = apply_filters( 'plugin_locale', get_locale(), 'wpai_woocommerce_addon_plugin' );
325
-
326
- load_plugin_textdomain( 'wpai_woocommerce_addon_plugin', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" );
327
- }
328
-
329
- /**
330
- * pre-dispatching logic for admin page controllers
331
- */
332
- public function adminInit() {
333
- $input = new PMWI_Input();
334
- $page = strtolower($input->getpost('page', ''));
335
- if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
336
- $this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
337
- }
338
- add_filter('plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
339
-
340
- }
341
-
342
- /**
343
- * Dispatch shorttag: create corresponding controller instance and call its index method
344
- * @param array $args Shortcode tag attributes
345
- * @param string $content Shortcode tag content
346
- * @param string $tag Shortcode tag name which is being dispatched
347
- * @return string
348
- */
349
- public function shortcodeDispatcher($args, $content, $tag) {
350
-
351
- $controllerName = self::PREFIX . preg_replace_callback('%(^|_).%', array($this, "replace_callback"), $tag);// capitalize first letters of class name parts and add prefix
352
- $controller = new $controllerName();
353
- if ( ! $controller instanceof PMWI_Controller) {
354
- throw new Exception("Shortcode `$tag` matches to a wrong controller type.");
355
- }
356
- ob_start();
357
- $controller->index($args, $content);
358
- return ob_get_clean();
359
- }
360
-
361
- public function replace_callback($matches){
362
- return strtoupper($matches[0]);
363
- }
364
-
365
- /**
366
- * Dispatch admin page: call corresponding controller based on get parameter `page`
367
- * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
368
- * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
369
- */
370
- public function adminDispatcher($page = '', $action = 'index') {
371
- static $buffer = NULL;
372
- static $buffer_callback = NULL;
373
- if ('' === $page) {
374
- if ( ! is_null($buffer)) {
375
- echo '<div class="wrap">';
376
- echo $buffer;
377
- do_action('PMWI_action_after');
378
- echo '</div>';
379
- } elseif ( ! is_null($buffer_callback)) {
380
- echo '<div class="wrap">';
381
- call_user_func($buffer_callback);
382
- do_action('PMWI_action_after');
383
- echo '</div>';
384
- } else {
385
- throw new Exception('There is no previousely buffered content to display.');
386
- }
387
- } else {
388
- $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page));
389
- $actionName = str_replace('-', '_', $action);
390
- if (method_exists($controllerName, $actionName)) {
391
-
392
- if ( ! get_current_user_id() or ! current_user_can('manage_options')) {
393
- // This nonce is not valid.
394
- die( 'Security check' );
395
-
396
- } else {
397
-
398
- $this->_admin_current_screen = (object)array(
399
- 'id' => $controllerName,
400
- 'base' => $controllerName,
401
- 'action' => $actionName,
402
- 'is_ajax' => isset($_SERVER['HTTP_X_REQUESTED_WITH']) and strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest',
403
- 'is_network' => is_network_admin(),
404
- 'is_user' => is_user_admin(),
405
- );
406
- add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
407
-
408
- $controller = new $controllerName();
409
- if ( ! $controller instanceof PMWI_Controller_Admin) {
410
- throw new Exception("Administration page `$page` matches to a wrong controller type.");
411
- }
412
-
413
- if ($this->_admin_current_screen->is_ajax) { // ajax request
414
- $controller->$action();
415
- do_action('PMWI_action_after');
416
- die(); // stop processing since we want to output only what controller is randered, nothing in addition
417
- } elseif ( ! $controller->isInline) {
418
- ob_start();
419
- $controller->$action();
420
- $buffer = ob_get_clean();
421
- } else {
422
- $buffer_callback = array($controller, $action);
423
- }
424
-
425
- }
426
-
427
- } else { // redirect to dashboard if requested page and/or action don't exist
428
- wp_redirect(admin_url()); die();
429
- }
430
- }
431
- }
432
-
433
- protected $_admin_current_screen = NULL;
434
- public function getAdminCurrentScreen()
435
- {
436
- return $this->_admin_current_screen;
437
- }
438
-
439
- /**
440
- * Autoloader
441
- * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
442
- * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
443
- * symbols after last `_` in class name)
444
- * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
445
- *
446
- * @param string $className
447
- * @return bool
448
- */
449
- public function autoload($className) {
450
- $is_prefix = false;
451
- $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
452
- if ( ! $is_prefix) { // also check file with original letter case
453
- $filePathAlt = $className . '.php';
454
- }
455
- foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array() as $subdir) {
456
- $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
457
- if (is_file($path)) {
458
- require $path;
459
- return TRUE;
460
- }
461
- if ( ! $is_prefix) {
462
- $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt;
463
- if (is_file($pathAlt)) {
464
- require $pathAlt;
465
- return TRUE;
466
- }
467
- }
468
- }
469
-
470
- return FALSE;
471
- }
472
-
473
- /**
474
- * Get plugin option
475
- * @param string[optional] $option Parameter to return, all array of options is returned if not set
476
- * @return mixed
477
- */
478
- public function getOption($option = NULL) {
479
- if (is_null($option)) {
480
- return $this->options;
481
- } else if (isset($this->options[$option])) {
482
- return $this->options[$option];
483
- } else {
484
- throw new Exception("Specified option is not defined for the plugin");
485
- }
486
- }
487
- /**
488
- * Update plugin option value
489
- * @param string $option Parameter name or array of name => value pairs
490
- * @param mixed[optional] $value New value for the option, if not set than 1st parameter is supposed to be array of name => value pairs
491
- * @return array
492
- */
493
- public function updateOption($option, $value = NULL) {
494
- is_null($value) or $option = array($option => $value);
495
- if (array_diff_key($option, $this->options)) {
496
- throw new Exception("Specified option is not defined for the plugin");
497
- }
498
- $this->options = $option + $this->options;
499
- update_option(get_class($this) . '_Options', $this->options);
500
-
501
- return $this->options;
502
- }
503
-
504
- /**
505
- * Plugin activation logic
506
- */
507
- public function activation() {
508
-
509
- // uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does
510
- set_exception_handler(function($e){trigger_error($e->getMessage(), E_USER_ERROR);});
511
-
512
- // create plugin options
513
- $option_name = get_class($this) . '_Options';
514
- $options_default = PMWI_Config::createFromFile(self::ROOT_DIR . '/config/options.php')->toArray();
515
- update_option($option_name, $options_default);
516
-
517
- }
518
-
519
- public function plugin_row_meta($links, $file)
520
- {
521
- if ( $file == plugin_basename( __FILE__ ) ) {
522
- $row_meta = array(
523
- 'pro' => '<a href="http://www.wpallimport.com/woocommerce-product-import/" target="_blank" title="' . esc_attr( __( 'WP All Import - WooCommerce Add-On Pro Version', 'wpai_woocommerce_addon_plugin' ) ) . '">' . __( 'Pro Version', 'wpai_woocommerce_addon_plugin' ) . '</a>',
524
- );
525
-
526
- return array_merge( $links, $row_meta );
527
- }
528
-
529
- return (array) $links;
530
- }
531
-
532
- /**
533
- * Method returns default import options, main utility of the method is to avoid warnings when new
534
- * option is introduced but already registered imports don't have it
535
- */
536
- public static function get_default_import_options() {
537
- return array(
538
- 'is_multiple_product_type' => 'yes',
539
- 'multiple_product_type' => 'simple',
540
- 'single_product_type' => '',
541
- 'is_product_virtual' => 'no',
542
- 'single_product_virtual' => '',
543
- 'is_product_downloadable' => 'no',
544
- 'single_product_downloadable' => '',
545
- 'is_product_enabled' => 'yes',
546
- 'single_product_enabled' => '',
547
- 'is_product_featured' => 'no',
548
- 'single_product_featured' => '',
549
- 'is_product_visibility' => 'visible',
550
- 'single_product_visibility' => '',
551
- 'single_product_sku' => '',
552
- 'single_product_url' => '',
553
- 'single_product_button_text' => '',
554
- 'single_product_regular_price' => '',
555
- 'single_product_sale_price' => '',
556
- 'single_product_files' => '',
557
- 'single_product_files_names' => '',
558
- 'single_product_download_limit' => '',
559
- 'single_product_download_expiry' => '',
560
- 'single_product_download_type' => '',
561
- 'is_multiple_product_tax_status' => 'yes',
562
- 'multiple_product_tax_status' => 'none',
563
- 'single_product_tax_status' => '',
564
- 'is_multiple_product_tax_class' => 'yes',
565
- 'multiple_product_tax_class' => '',
566
- 'single_product_tax_class' => '',
567
- 'is_product_manage_stock' => 'no',
568
- 'single_product_manage_stock' => '',
569
- 'single_product_stock_qty' => '',
570
- 'product_stock_status' => 'auto',
571
- 'single_product_stock_status' => '',
572
- 'product_allow_backorders' => 'no',
573
- 'single_product_allow_backorders' => '',
574
- 'product_sold_individually' => 'no',
575
- 'single_product_sold_individually' => '',
576
- 'single_product_weight' => '',
577
- 'single_product_length' => '',
578
- 'single_product_width' => '',
579
- 'single_product_height' => '',
580
- 'is_multiple_product_shipping_class' => 'yes',
581
- 'multiple_product_shipping_class' => '',
582
- 'single_product_shipping_class' => '',
583
- 'is_multiple_grouping_product' => 'yes',
584
- 'multiple_grouping_product' => '',
585
- 'single_grouping_product' => '',
586
- 'single_product_up_sells' => '',
587
- 'single_product_cross_sells' => '',
588
- 'attribute_name' => array(),
589
- 'attribute_value' => array(),
590
- 'in_variations' => array(),
591
- 'is_visible' => array(),
592
- 'is_taxonomy' => array(),
593
- 'create_taxonomy_in_not_exists' => array(),
594
-
595
- 'is_advanced' => array(),
596
- 'advanced_in_variations' => array(),
597
- 'advanced_in_variations_xpath' => array(),
598
- 'advanced_is_visible' => array(),
599
- 'advanced_is_visible_xpath' => array(),
600
- 'advanced_is_taxonomy' => array(),
601
- 'advanced_is_taxonomy_xpath' => array(),
602
- 'advanced_is_create_terms' => array(),
603
- 'advanced_is_create_terms_xpath' => array(),
604
-
605
- 'single_product_purchase_note' => '',
606
- 'single_product_menu_order' => 0,
607
- 'is_product_enable_reviews' => 'no',
608
- 'single_product_enable_reviews' => '',
609
- 'single_product_id' => '',
610
- 'single_product_parent_id' => '',
611
- 'single_product_id_first_is_parent_id' => '',
612
- 'single_product_id_first_is_parent_title' => '',
613
- 'single_product_id_first_is_variation' => '',
614
- '_virtual' => 0,
615
- '_downloadable' => 0,
616
- 'is_regular_price_shedule' => 0,
617
- 'single_sale_price_dates_from' => 'now',
618
- 'single_sale_price_dates_to' => 'now',
619
- 'product_files_delim' => ',',
620
- 'product_files_names_delim' => ',',
621
- 'matching_parent' => 'auto',
622
- 'parent_indicator' => 'custom field',
623
- 'custom_parent_indicator_name' => '',
624
- 'custom_parent_indicator_value' => '',
625
- 'missing_records_stock_status' => 0,
626
- 'variations_xpath' => '',
627
- '_variable_virtual' => '',
628
- '_variable_downloadable' => '',
629
- 'variable_stock' => '',
630
- 'variable_regular_price' => '',
631
- 'variable_sale_price' => '',
632
- 'is_variable_sale_price_shedule' => 0,
633
- 'variable_sale_price_dates_from' => '',
634
- 'variable_sale_price_dates_to' => '',
635
- 'variable_weight' => '',
636
- 'variable_length' => '',
637
- 'variable_width' => '',
638
- 'variable_height' => '',
639
- 'variable_shipping_class' => '',
640
- 'variable_tax_class' => '',
641
- 'variable_file_paths' => '',
642
- 'variable_file_names' => '',
643
- 'variable_download_limit' => '',
644
- 'variable_download_expiry' => '',
645
- 'is_variable_product_virtual' => 'no',
646
- 'is_variable_product_manage_stock' => 'no',
647
- 'is_multiple_variable_product_shipping_class' => 'yes',
648
- 'multiple_variable_product_shipping_class' => '',
649
- 'single_variable_product_shipping_class' => '',
650
- 'is_multiple_variable_product_tax_class' => 'yes',
651
- 'multiple_variable_product_tax_class' => 'parent',
652
- 'single_variable_product_tax_class' => '',
653
- 'variable_stock_status' => 'instock',
654
- 'single_variable_stock_status' => '',
655
- 'variable_allow_backorders' => 'no',
656
- 'single_variable_allow_backorders' => '',
657
- 'is_variable_product_downloadable' => 'no',
658
- 'single_variable_product_downloadable' => '',
659
- 'variable_attribute_name' => array(),
660
- 'variable_attribute_value' => array(),
661
- 'variable_in_variations' => array(),
662
- 'variable_is_visible' => array(),
663
- 'variable_is_taxonomy' => array(),
664
- 'variable_create_taxonomy_in_not_exists' => array(),
665
- 'variable_product_files_delim' => ',',
666
- 'variable_product_files_names_delim' => ',',
667
- 'variable_image' => '',
668
- 'variable_sku' => '',
669
- 'is_variable_product_enabled' => 'yes',
670
- 'single_variable_product_enabled' => '',
671
- 'link_all_variations' => 0,
672
- 'variable_stock_use_parent' => 0,
673
- 'variable_regular_price_use_parent' => 0,
674
- 'variable_sale_price_use_parent' => 0,
675
- 'variable_sale_dates_use_parent' => 0,
676
- 'variable_weight_use_parent' => 0,
677
- 'single_variable_product_virtual' => '',
678
- 'single_variable_product_virtual_use_parent' => 0,
679
- 'single_variable_product_manage_stock' => '',
680
- 'single_variable_product_manage_stock_use_parent' => 0,
681
- 'variable_dimensions_use_parent' => 0,
682
- 'variable_image_use_parent' => 0,
683
- 'single_variable_product_shipping_class_use_parent' => 0,
684
- 'single_variable_product_tax_class_use_parent' => 0,
685
- 'single_variable_product_downloadable_use_parent' => 0,
686
- 'variable_download_limit_use_parent' => 0,
687
- 'variable_download_expiry_use_parent' => 0,
688
-
689
- 'single_product_variation_description' => '',
690
- 'variable_description' => '',
691
- 'variable_description_use_parent' => 0,
692
-
693
- 'first_is_parent' => 'yes',
694
- 'single_product_whosale_price' => '',
695
- 'variable_whosale_price' => '',
696
- 'variable_whosale_price_use_parent' => 0,
697
- 'disable_auto_sku_generation' => 0,
698
- 'is_default_attributes' => 0,
699
- 'default_attributes_type' => 'first',
700
- 'disable_sku_matching' => 1,
701
- 'disable_prepare_price' => 1,
702
- 'prepare_price_to_woo_format' => 0,
703
- 'convert_decimal_separator' => 1,
704
- 'grouping_indicator' => 'xpath',
705
- 'custom_grouping_indicator_name' => '',
706
- 'custom_grouping_indicator_value' => '',
707
- 'is_update_product_type' => 1,
708
- 'make_simple_product' => 1,
709
- 'variable_sku_add_parent' => 0,
710
- 'set_parent_stock' => 0,
711
- 'single_product_regular_price_adjust' => '',
712
- 'single_product_regular_price_adjust_type' => '%',
713
- 'single_product_sale_price_adjust' => '',
714
- 'single_product_sale_price_adjust_type' => '%',
715
-
716
- 'is_update_attributes' => 1,
717
- 'update_attributes_logic' => 'full_update',
718
- 'attributes_list' => array(),
719
- 'attributes_only_list' => array(),
720
- 'attributes_except_list' => array(),
721
-
722
- 'is_variation_product_manage_stock' => 'no',
723
- 'single_variation_product_manage_stock' => '',
724
- 'variation_stock' => '',
725
- 'variation_stock_status' => 'auto',
726
- 'put_variation_image_to_gallery' => 0,
727
- 'single_variation_stock_status' => '',
728
- 'is_update_advanced_options' => 1,
729
- 'is_update_catalog_visibility' => 1,
730
- 'is_update_featured_status' => 1
731
- );
732
- }
733
- }
734
 
735
- PMWI_Plugin::getInstance();
 
 
736
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  Plugin Name: WP All Import - WooCommerce Add-On
4
  Plugin URI: http://www.wpallimport.com/
5
  Description: An extremely easy, drag & drop importer to import WooCommerce simple products. A paid upgrade is available for premium support and support for Variable, Grouped, and External/Affiliate products
6
+ Version: 1.4.0
7
  Author: Soflyy
8
+ WC tested up to: 3.6.0
9
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ if ( ! function_exists( 'is_plugin_active' ) ) {
12
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
13
+ }
14
 
15
+ if ( is_plugin_active('wpai-woocommerce-add-on/wpai-woocommerce-add-on.php') ) {
16
+ function pmwi_free_notice() {
17
+ ?>
18
+ <div class="error"><p>
19
+ <?php printf(__('The Pro version of the WooCommerce Add-On is already installed. If you intended to replace it with the free version, please de-activate and remove the paid version before activating the free version.', 'wpai_woocommerce_addon_plugin')); ?>
20
+ </p></div>
21
+ <?php
22
+ }
23
+ add_action('admin_notices', 'pmwi_free_notice');
24
+ deactivate_plugins(str_replace('\\', '/', dirname(__FILE__)) . '/plugin.php');
25
+ }
26
+ else {
27
+
28
+ define('PMWI_FREE_VERSION', '1.4.0');
29
+
30
+ define('PMWI_EDITION', 'free');
31
+
32
+ /**
33
+ * Plugin root dir with forward slashes as directory separator regardless of actuall DIRECTORY_SEPARATOR value
34
+ * @var string
35
+ */
36
+ define('PMWI_ROOT_DIR', str_replace('\\', '/', dirname(__FILE__)));
37
+
38
+ /**
39
+ * Plugin root url for referencing static content
40
+ * @var string
41
+ */
42
+ define('PMWI_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
43
+
44
+ /**
45
+ * Plugin prefix for making names unique (be aware that this variable is used in conjuction with naming convention,
46
+ * i.e. in order to change it one must not only modify this constant but also rename all constants, classes and functions which
47
+ * names composed using this prefix)
48
+ * @var string
49
+ */
50
+ define('PMWI_PREFIX', 'pmwi_');
51
+
52
+ /**
53
+ * Main plugin file, Introduces MVC pattern
54
+ *
55
+ * @singletone
56
+ * @author Maksym Tsypliakov <maksym.tsypliakov@gmail.com>
57
+ */
58
+ final class PMWI_Plugin {
59
+ /**
60
+ * Singletone instance
61
+ * @var PMWI_Plugin
62
+ */
63
+ protected static $instance;
64
+
65
+ /**
66
+ * Plugin root dir
67
+ * @var string
68
+ */
69
+ const ROOT_DIR = PMWI_ROOT_DIR;
70
+ /**
71
+ * Plugin root URL
72
+ * @var string
73
+ */
74
+ const ROOT_URL = PMWI_ROOT_URL;
75
+ /**
76
+ * Prefix used for names of shortcodes, action handlers, filter functions etc.
77
+ * @var string
78
+ */
79
+ const PREFIX = PMWI_PREFIX;
80
+ /**
81
+ * Plugin file path
82
+ * @var string
83
+ */
84
+ const FILE = __FILE__;
85
+ /**
86
+ * Plugin text domain
87
+ * @var string
88
+ */
89
+ const TEXT_DOMAIN = 'wpai_woocommerce_addon_plugin';
90
+
91
+ /**
92
+ * Return singletone instance
93
+ * @return PMWI_Plugin
94
+ */
95
+ static public function getInstance() {
96
+ if (self::$instance == NULL) {
97
+ self::$instance = new self();
98
+ }
99
+ return self::$instance;
100
+ }
101
+
102
+ /**
103
+ * Common logic for requestin plugin info fields
104
+ */
105
+ public function __call($method, $args) {
106
+ if (preg_match('%^get(.+)%i', $method, $mtch)) {
107
+ $info = get_plugin_data(self::FILE);
108
+ if (isset($info[$mtch[1]])) {
109
+ return $info[$mtch[1]];
110
+ }
111
+ }
112
+ throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
113
+ }
114
+
115
+ /**
116
+ * Get path to plagin dir relative to wordpress root
117
+ * @param bool[optional] $noForwardSlash Whether path should be returned withot forwarding slash
118
+ * @return string
119
+ */
120
+ public function getRelativePath($noForwardSlash = false) {
121
+ $wp_root = str_replace('\\', '/', ABSPATH);
122
+ return ($noForwardSlash ? '' : '/') . str_replace($wp_root, '', self::ROOT_DIR);
123
+ }
124
+
125
+ /**
126
+ * Check whether plugin is activated as network one
127
+ * @return bool
128
+ */
129
+ public function isNetwork() {
130
+ if ( !is_multisite() )
131
+ return false;
132
+
133
+ $plugins = get_site_option('active_sitewide_plugins');
134
+ if (isset($plugins[plugin_basename(self::FILE)]))
135
+ return true;
136
+
137
+ return false;
138
+ }
139
+
140
+ /**
141
+ * Check whether permalinks is enabled
142
+ * @return bool
143
+ */
144
+ public function isPermalinks() {
145
+ global $wp_rewrite;
146
+
147
+ return $wp_rewrite->using_permalinks();
148
+ }
149
+
150
+ /**
151
+ * Return prefix for plugin database tables
152
+ * @return string
153
+ */
154
+ public function getTablePrefix() {
155
+ global $wpdb;
156
+ return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix) . self::PREFIX;
157
+ }
158
+
159
+ /**
160
+ * Return prefix for wordpress database tables
161
+ * @return string
162
+ */
163
+ public function getWPPrefix() {
164
+ global $wpdb;
165
+ return ($this->isNetwork() ? $wpdb->base_prefix : $wpdb->prefix);
166
+ }
167
+
168
+ /**
169
+ * Class constructor containing dispatching logic
170
+ * @param string $rootDir Plugin root dir
171
+ * @param string $pluginFilePath Plugin main file
172
+ */
173
+ protected function __construct() {
174
+
175
+ // create/update required database tables
176
+
177
+ // register autoloading method
178
+ spl_autoload_register(array($this, 'autoload'));
179
+
180
+ // register helpers
181
+ if (is_dir(self::ROOT_DIR . '/helpers')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/helpers/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
182
+ require_once $filePath;
183
+ }
184
+
185
+ register_activation_hook(self::FILE, array($this, 'activation'));
186
+
187
+ // register action handlers
188
+ if (is_dir(self::ROOT_DIR . '/actions')) if (is_dir(self::ROOT_DIR . '/actions')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/actions/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
189
+ require_once $filePath;
190
+ $function = $actionName = basename($filePath, '.php');
191
+ if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
192
+ $actionName = $m[1];
193
+ $priority = intval($m[2]);
194
+ } else {
195
+ $priority = 10;
196
+ }
197
+ add_action($actionName, self::PREFIX . str_replace('-', '_', $function), $priority, 99); // since we don't know at this point how many parameters each plugin expects, we make sure they will be provided with all of them (it's unlikely any developer will specify more than 99 parameters in a function)
198
+ }
199
+
200
+ // register filter handlers
201
+ if (is_dir(self::ROOT_DIR . '/filters')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/filters/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
202
+ require_once $filePath;
203
+ $function = $actionName = basename($filePath, '.php');
204
+ if (preg_match('%^(.+?)[_-](\d+)$%', $actionName, $m)) {
205
+ $actionName = $m[1];
206
+ $priority = intval($m[2]);
207
+ } else {
208
+ $priority = 10;
209
+ }
210
+ add_filter($actionName, self::PREFIX . str_replace('-', '_', $function), $priority, 99); // since we don't know at this point how many parameters each plugin expects, we make sure they will be provided with all of them (it's unlikely any developer will specify more than 99 parameters in a function)
211
+ }
212
+
213
+ // register shortcodes handlers
214
+ if (is_dir(self::ROOT_DIR . '/shortcodes')) foreach (PMWI_Helper::safe_glob(self::ROOT_DIR . '/shortcodes/*.php', PMWI_Helper::GLOB_RECURSE | PMWI_Helper::GLOB_PATH) as $filePath) {
215
+ $tag = strtolower(str_replace('/', '_', preg_replace('%^' . preg_quote(self::ROOT_DIR . '/shortcodes/', '%') . '|\.php$%', '', $filePath)));
216
+ add_shortcode($tag, array($this, 'shortcodeDispatcher'));
217
+ }
218
+
219
+ // register admin page pre-dispatcher
220
+ add_action('admin_init', array($this, 'adminInit'));
221
+ add_action('admin_init', array($this, 'migrate_options'));
222
+ add_action('init', array($this, 'init'));
223
+
224
+ }
225
+
226
+ public function migrate_options(){
227
+
228
+ $installed_ver = get_option( "wp_all_import_woocommerce_addon_db_version" );
229
+
230
+ if ( $installed_ver == PMWI_FREE_VERSION || ! class_exists( 'PMXI_Plugin' ) ) return true;
231
+
232
+ $imports = new PMXI_Import_List();
233
+
234
+ $templates = new PMXI_Template_List();
235
+
236
+ foreach ($imports->setColumns($imports->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $imp){
237
+ $imp->getById($imp->id);
238
+ if ( ! $imp->isEmpty() ){
239
+ $options = $imp->options;
240
+ $this->migrate($options, $installed_ver);
241
+ $imp->set(array(
242
+ 'options' => $options
243
+ ))->update();
244
+ }
245
+ }
246
+
247
+ foreach ($templates->setColumns($templates->getTable() . '.*')->getBy(array('id !=' => ''))->convertRecords() as $tpl){
248
+ $tpl->getById($tpl->id);
249
+ if ( ! $tpl->isEmpty() ) {
250
+ $options = ( empty($tpl->options) ) ? array() : $tpl->options;
251
+ $this->migrate($options, $installed_ver);
252
+ $tpl->set(array(
253
+ 'options' => $options
254
+ ))->update();
255
+ }
256
+ }
257
+ update_option( "wp_all_import_woocommerce_addon_db_version", PMWI_FREE_VERSION );
258
+ }
259
+
260
+ private function migrate(&$options, $version){
261
+
262
+ // Update _featured, _visibility and _stock_status options according to WooCommerce 3.0
263
+ if ( version_compare($version, '2.3.7-beta-2.1') < 0 ){
264
+
265
+ $remove_cf = array('_featured', '_visibility', '_stock_status');
266
+
267
+ if ($options['is_keep_former_posts'] == 'no'
268
+ && $options['update_all_data'] == 'no'){
269
+
270
+ if ($options['is_update_custom_fields']){
271
+ if (in_array($options['update_custom_fields_logic'], array('only', 'all_except'))){
272
+ // Update Options
273
+ switch ($options['update_custom_fields_logic']){
274
+ case 'only':
275
+ $fields_list = explode(',', $options['custom_fields_only_list']);
276
+ if ( ! in_array('_featured', $fields_list) ){
277
+ $options['is_update_featured_status'] = 0;
278
+ }
279
+ if ( ! in_array('_visibility', $fields_list) ){
280
+ $options['is_update_catalog_visibility'] = 0;
281
+ }
282
+ break;
283
+ case 'all_except':
284
+ $fields_list = explode(',', $options['custom_fields_except_list']);
285
+ if ( in_array('_featured', $fields_list) ){
286
+ $options['is_update_featured_status'] = 0;
287
+ }
288
+ if ( in_array('_visibility', $fields_list) ){
289
+ $options['is_update_catalog_visibility'] = 0;
290
+ }
291
+ break;
292
+ }
293
+ }
294
+ }
295
+ else{
296
+ $options['is_update_advanced_options'] = 0;
297
+ $options['is_update_featured_status'] = 0;
298
+ $options['is_update_catalog_visibility'] = 0;
299
+ }
300
+ }
301
+
302
+ // remove deprecated fields from custom fields list
303
+ $options_to_update = array('custom_fields_list', 'custom_fields_only_list', 'custom_fields_except_list');
304
+ foreach ($options_to_update as $option){
305
+ if ( ! empty($options[$option])){
306
+ $fields_list = is_array($options[$option]) ? $options[$option] : explode(',', $options[$option]);
307
+ foreach ($fields_list as $key => $value){
308
+ if (in_array($value, $remove_cf)){
309
+ unset($fields_list[$key]);
310
+ }
311
+ }
312
+ $options[$option] = is_array($options[$option]) ? $fields_list : implode(',', $fields_list);
313
+ }
314
+ }
315
+ }
316
+ }
317
+
318
+ public function init()
319
+ {
320
+ $this->load_plugin_textdomain();
321
+ }
322
+
323
+ /**
324
+ * Load Localisation files.
325
+ *
326
+ * Note: the first-loaded translation file overrides any following ones if the same translation is present
327
+ *
328
+ * @access public
329
+ * @return void
330
+ */
331
+ public function load_plugin_textdomain() {
332
+
333
+ $locale = apply_filters( 'plugin_locale', get_locale(), 'wpai_woocommerce_addon_plugin' );
334
+
335
+ load_plugin_textdomain( 'wpai_woocommerce_addon_plugin', false, dirname( plugin_basename( __FILE__ ) ) . "/i18n/languages" );
336
+ }
337
+
338
+ /**
339
+ * pre-dispatching logic for admin page controllers
340
+ */
341
+ public function adminInit() {
342
+ $input = new PMWI_Input();
343
+ $page = strtolower($input->getpost('page', ''));
344
+ if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
345
+ $this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
346
+ }
347
+ add_filter('plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
348
+
349
+ }
350
+
351
+ /**
352
+ * Dispatch shorttag: create corresponding controller instance and call its index method
353
+ * @param array $args Shortcode tag attributes
354
+ * @param string $content Shortcode tag content
355
+ * @param string $tag Shortcode tag name which is being dispatched
356
+ * @return string
357
+ */
358
+ public function shortcodeDispatcher($args, $content, $tag) {
359
+
360
+ $controllerName = self::PREFIX . preg_replace_callback('%(^|_).%', array($this, "replace_callback"), $tag);// capitalize first letters of class name parts and add prefix
361
+ $controller = new $controllerName();
362
+ if ( ! $controller instanceof PMWI_Controller) {
363
+ throw new Exception("Shortcode `$tag` matches to a wrong controller type.");
364
+ }
365
+ ob_start();
366
+ $controller->index($args, $content);
367
+ return ob_get_clean();
368
+ }
369
+
370
+ public function replace_callback($matches){
371
+ return strtoupper($matches[0]);
372
+ }
373
+
374
+ /**
375
+ * Dispatch admin page: call corresponding controller based on get parameter `page`
376
+ * The method is called twice: 1st time as handler `parse_header` action and then as admin menu item handler
377
+ * @param string[optional] $page When $page set to empty string ealier buffered content is outputted, otherwise controller is called based on $page value
378
+ */
379
+ public function adminDispatcher($page = '', $action = 'index') {
380
+ static $buffer = NULL;
381
+ static $buffer_callback = NULL;
382
+ if ('' === $page) {
383
+ if ( ! is_null($buffer)) {
384
+ echo '<div class="wrap">';
385
+ echo $buffer;
386
+ do_action('PMWI_action_after');
387
+ echo '</div>';
388
+ } elseif ( ! is_null($buffer_callback)) {
389
+ echo '<div class="wrap">';
390
+ call_user_func($buffer_callback);
391
+ do_action('PMWI_action_after');
392
+ echo '</div>';
393
+ } else {
394
+ throw new Exception('There is no previousely buffered content to display.');
395
+ }
396
+ } else {
397
+ $controllerName = preg_replace_callback('%(^' . preg_quote(self::PREFIX, '%') . '|_).%', array($this, "replace_callback"),str_replace('-', '_', $page));
398
+ $actionName = str_replace('-', '_', $action);
399
+ if (method_exists($controllerName, $actionName)) {
400
+
401
+ if ( ! get_current_user_id() or ! current_user_can('manage_options')) {
402
+ // This nonce is not valid.
403
+ die( 'Security check' );
404
+
405
+ } else {
406
+
407
+ $this->_admin_current_screen = (object)array(
408
+ 'id' => $controllerName,
409
+ 'base' => $controllerName,
410
+ 'action' => $actionName,
411
+ 'is_ajax' => isset($_SERVER['HTTP_X_REQUESTED_WITH']) and strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest',
412
+ 'is_network' => is_network_admin(),
413
+ 'is_user' => is_user_admin(),
414
+ );
415
+ add_filter('current_screen', array($this, 'getAdminCurrentScreen'));
416
+
417
+ $controller = new $controllerName();
418
+ if ( ! $controller instanceof PMWI_Controller_Admin) {
419
+ throw new Exception("Administration page `$page` matches to a wrong controller type.");
420
+ }
421
+
422
+ if ($this->_admin_current_screen->is_ajax) { // ajax request
423
+ $controller->$action();
424
+ do_action('PMWI_action_after');
425
+ die(); // stop processing since we want to output only what controller is randered, nothing in addition
426
+ } elseif ( ! $controller->isInline) {
427
+ ob_start();
428
+ $controller->$action();
429
+ $buffer = ob_get_clean();
430
+ } else {
431
+ $buffer_callback = array($controller, $action);
432
+ }
433
+
434
+ }
435
+
436
+ } else { // redirect to dashboard if requested page and/or action don't exist
437
+ wp_redirect(admin_url()); die();
438
+ }
439
+ }
440
+ }
441
+
442
+ protected $_admin_current_screen = NULL;
443
+ public function getAdminCurrentScreen()
444
+ {
445
+ return $this->_admin_current_screen;
446
+ }
447
+
448
+ /**
449
+ * Autoloader
450
+ * It's assumed class name consists of prefix folloed by its name which in turn corresponds to location of source file
451
+ * if `_` symbols replaced by directory path separator. File name consists of prefix folloed by last part in class name (i.e.
452
+ * symbols after last `_` in class name)
453
+ * When class has prefix it's source is looked in `models`, `controllers`, `shortcodes` folders, otherwise it looked in `core` or `library` folder
454
+ *
455
+ * @param string $className
456
+ * @return bool
457
+ */
458
+ public function autoload($className) {
459
+ $is_prefix = false;
460
+ $filePath = str_replace('_', '/', preg_replace('%^' . preg_quote(self::PREFIX, '%') . '%', '', strtolower($className), 1, $is_prefix)) . '.php';
461
+ if ( ! $is_prefix) { // also check file with original letter case
462
+ $filePathAlt = $className . '.php';
463
+ }
464
+ foreach ($is_prefix ? array('models', 'controllers', 'shortcodes', 'classes') : array() as $subdir) {
465
+ $path = self::ROOT_DIR . '/' . $subdir . '/' . $filePath;
466
+ if (is_file($path)) {
467
+ require $path;
468
+ return TRUE;
469
+ }
470
+ if ( ! $is_prefix) {
471
+ $pathAlt = self::ROOT_DIR . '/' . $subdir . '/' . $filePathAlt;
472
+ if (is_file($pathAlt)) {
473
+ require $pathAlt;
474
+ return TRUE;
475
+ }
476
+ }
477
+ }
478
+
479
+ return FALSE;
480
+ }
481
+
482
+ /**
483
+ * Plugin activation logic
484
+ */
485
+ public function activation() {
486
+ // Uncaught exception doesn't prevent plugin from being activated, therefore replace it with fatal error so it does.
487
+ set_exception_handler(function($e){trigger_error($e->getMessage(), E_USER_ERROR);});
488
+ }
489
+
490
+ public function plugin_row_meta($links, $file)
491
+ {
492
+ if ( $file == plugin_basename( __FILE__ ) ) {
493
+ $row_meta = array(
494
+ 'pro' => '<a href="http://www.wpallimport.com/woocommerce-product-import/" target="_blank" title="' . esc_attr( __( 'WP All Import - WooCommerce Add-On Pro Version', 'wpai_woocommerce_addon_plugin' ) ) . '">' . __( 'Pro Version', 'wpai_woocommerce_addon_plugin' ) . '</a>',
495
+ );
496
+
497
+ return array_merge( $links, $row_meta );
498
+ }
499
+
500
+ return (array) $links;
501
+ }
502
+
503
+ /**
504
+ * Method returns default import options, main utility of the method is to avoid warnings when new
505
+ * option is introduced but already registered imports don't have it
506
+ */
507
+ public static function get_default_import_options() {
508
+ return array(
509
+ 'is_multiple_product_type' => 'yes',
510
+ 'multiple_product_type' => 'simple',
511
+ 'single_product_type' => '',
512
+ 'is_product_virtual' => 'no',
513
+ 'single_product_virtual' => '',
514
+ 'is_product_downloadable' => 'no',
515
+ 'single_product_downloadable' => '',
516
+ 'is_product_enabled' => 'yes',
517
+ 'single_product_enabled' => '',
518
+ 'is_product_featured' => 'no',
519
+ 'single_product_featured' => '',
520
+ 'is_product_visibility' => 'visible',
521
+ 'single_product_visibility' => '',
522
+ 'single_product_sku' => '',
523
+ 'single_product_url' => '',
524
+ 'single_product_button_text' => '',
525
+ 'single_product_regular_price' => '',
526
+ 'single_product_sale_price' => '',
527
+ 'single_product_files' => '',
528
+ 'single_product_files_names' => '',
529
+ 'single_product_download_limit' => '',
530
+ 'single_product_download_expiry' => '',
531
+ 'single_product_download_type' => '',
532
+ 'is_multiple_product_tax_status' => 'yes',
533
+ 'multiple_product_tax_status' => 'none',
534
+ 'single_product_tax_status' => '',
535
+ 'is_multiple_product_tax_class' => 'yes',
536
+ 'multiple_product_tax_class' => '',
537
+ 'single_product_tax_class' => '',
538
+ 'is_product_manage_stock' => 'no',
539
+ 'single_product_manage_stock' => '',
540
+ 'single_product_stock_qty' => '',
541
+ 'product_stock_status' => 'auto',
542
+ 'single_product_stock_status' => '',
543
+ 'product_allow_backorders' => 'no',
544
+ 'single_product_allow_backorders' => '',
545
+ 'product_sold_individually' => 'no',
546
+ 'single_product_sold_individually' => '',
547
+ 'single_product_weight' => '',
548
+ 'single_product_length' => '',
549
+ 'single_product_width' => '',
550
+ 'single_product_height' => '',
551
+ 'is_multiple_product_shipping_class' => 'yes',
552
+ 'multiple_product_shipping_class' => '',
553
+ 'single_product_shipping_class' => '',
554
+ 'is_multiple_grouping_product' => 'yes',
555
+ 'multiple_grouping_product' => '',
556
+ 'single_grouping_product' => '',
557
+ 'single_product_up_sells' => '',
558
+ 'single_product_cross_sells' => '',
559
+ 'attribute_name' => array(),
560
+ 'attribute_value' => array(),
561
+ 'in_variations' => array(),
562
+ 'is_visible' => array(),
563
+ 'is_taxonomy' => array(),
564
+ 'create_taxonomy_in_not_exists' => array(),
565
+
566
+ 'is_advanced' => array(),
567
+ 'advanced_in_variations' => array(),
568
+ 'advanced_in_variations_xpath' => array(),
569
+ 'advanced_is_visible' => array(),
570
+ 'advanced_is_visible_xpath' => array(),
571
+ 'advanced_is_taxonomy' => array(),
572
+ 'advanced_is_taxonomy_xpath' => array(),
573
+ 'advanced_is_create_terms' => array(),
574
+ 'advanced_is_create_terms_xpath' => array(),
575
+
576
+ 'single_product_purchase_note' => '',
577
+ 'single_product_menu_order' => 0,
578
+ 'is_product_enable_reviews' => 'no',
579
+ 'single_product_enable_reviews' => '',
580
+ 'single_product_id' => '',
581
+ 'single_product_parent_id' => '',
582
+ 'single_product_id_first_is_parent_id' => '',
583
+ 'single_product_id_first_is_parent_title' => '',
584
+ 'single_product_id_first_is_variation' => '',
585
+ '_virtual' => 0,
586
+ '_downloadable' => 0,
587
+ 'is_regular_price_shedule' => 0,
588
+ 'single_sale_price_dates_from' => 'now',
589
+ 'single_sale_price_dates_to' => 'now',
590
+ 'product_files_delim' => ',',
591
+ 'product_files_names_delim' => ',',
592
+ 'matching_parent' => 'auto',
593
+ 'parent_indicator' => 'custom field',
594
+ 'custom_parent_indicator_name' => '',
595
+ 'custom_parent_indicator_value' => '',
596
+ 'missing_records_stock_status' => 0,
597
+ 'variations_xpath' => '',
598
+ '_variable_virtual' => '',
599
+ '_variable_downloadable' => '',
600
+ 'variable_stock' => '',
601
+ 'variable_regular_price' => '',
602
+ 'variable_sale_price' => '',
603
+ 'is_variable_sale_price_shedule' => 0,
604
+ 'variable_sale_price_dates_from' => '',
605
+ 'variable_sale_price_dates_to' => '',
606
+ 'variable_weight' => '',
607
+ 'variable_length' => '',
608
+ 'variable_width' => '',
609
+ 'variable_height' => '',
610
+ 'variable_shipping_class' => '',
611
+ 'variable_tax_class' => '',
612
+ 'variable_file_paths' => '',
613
+ 'variable_file_names' => '',
614
+ 'variable_download_limit' => '',
615
+ 'variable_download_expiry' => '',
616
+ 'is_variable_product_virtual' => 'no',
617
+ 'is_variable_product_manage_stock' => 'no',
618
+ 'is_multiple_variable_product_shipping_class' => 'yes',
619
+ 'multiple_variable_product_shipping_class' => '',
620
+ 'single_variable_product_shipping_class' => '',
621
+ 'is_multiple_variable_product_tax_class' => 'yes',
622
+ 'multiple_variable_product_tax_class' => 'parent',
623
+ 'single_variable_product_tax_class' => '',
624
+ 'variable_stock_status' => 'instock',
625
+ 'single_variable_stock_status' => '',
626
+ 'variable_allow_backorders' => 'no',
627
+ 'single_variable_allow_backorders' => '',
628
+ 'is_variable_product_downloadable' => 'no',
629
+ 'single_variable_product_downloadable' => '',
630
+ 'variable_attribute_name' => array(),
631
+ 'variable_attribute_value' => array(),
632
+ 'variable_in_variations' => array(),
633
+ 'variable_is_visible' => array(),
634
+ 'variable_is_taxonomy' => array(),
635
+ 'variable_create_taxonomy_in_not_exists' => array(),
636
+ 'variable_product_files_delim' => ',',
637
+ 'variable_product_files_names_delim' => ',',
638
+ 'variable_image' => '',
639
+ 'variable_sku' => '',
640
+ 'is_variable_product_enabled' => 'yes',
641
+ 'single_variable_product_enabled' => '',
642
+ 'link_all_variations' => 0,
643
+ 'variable_stock_use_parent' => 0,
644
+ 'variable_regular_price_use_parent' => 0,
645
+ 'variable_sale_price_use_parent' => 0,
646
+ 'variable_sale_dates_use_parent' => 0,
647
+ 'variable_weight_use_parent' => 0,
648
+ 'single_variable_product_virtual' => '',
649
+ 'single_variable_product_virtual_use_parent' => 0,
650
+ 'single_variable_product_manage_stock' => '',
651
+ 'single_variable_product_manage_stock_use_parent' => 0,
652
+ 'variable_dimensions_use_parent' => 0,
653
+ 'variable_image_use_parent' => 0,
654
+ 'single_variable_product_shipping_class_use_parent' => 0,
655
+ 'single_variable_product_tax_class_use_parent' => 0,
656
+ 'single_variable_product_downloadable_use_parent' => 0,
657
+ 'variable_download_limit_use_parent' => 0,
658
+ 'variable_download_expiry_use_parent' => 0,
659
+
660
+ 'single_product_variation_description' => '',
661
+ 'variable_description' => '',
662
+ 'variable_description_use_parent' => 0,
663
+
664
+ 'first_is_parent' => 'yes',
665
+ 'single_product_whosale_price' => '',
666
+ 'variable_whosale_price' => '',
667
+ 'variable_whosale_price_use_parent' => 0,
668
+ 'disable_auto_sku_generation' => 0,
669
+ 'is_default_attributes' => 0,
670
+ 'default_attributes_type' => 'first',
671
+ 'disable_sku_matching' => 1,
672
+ 'disable_prepare_price' => 1,
673
+ 'prepare_price_to_woo_format' => 0,
674
+ 'convert_decimal_separator' => 1,
675
+ 'grouping_indicator' => 'xpath',
676
+ 'custom_grouping_indicator_name' => '',
677
+ 'custom_grouping_indicator_value' => '',
678
+ 'is_update_product_type' => 1,
679
+ 'make_simple_product' => 1,
680
+ 'variable_sku_add_parent' => 0,
681
+ 'set_parent_stock' => 0,
682
+ 'single_product_regular_price_adjust' => '',
683
+ 'single_product_regular_price_adjust_type' => '%',
684
+ 'single_product_sale_price_adjust' => '',
685
+ 'single_product_sale_price_adjust_type' => '%',
686
+
687
+ 'is_update_attributes' => 1,
688
+ 'update_attributes_logic' => 'full_update',
689
+ 'attributes_list' => array(),
690
+ 'attributes_only_list' => array(),
691
+ 'attributes_except_list' => array(),
692
+
693
+ 'is_variation_product_manage_stock' => 'no',
694
+ 'single_variation_product_manage_stock' => '',
695
+ 'variation_stock' => '',
696
+ 'variation_stock_status' => 'auto',
697
+ 'put_variation_image_to_gallery' => 0,
698
+ 'single_variation_stock_status' => '',
699
+ 'is_update_advanced_options' => 1,
700
+ 'is_update_catalog_visibility' => 1,
701
+ 'is_update_featured_status' => 1
702
+ );
703
+ }
704
+ }
705
+
706
+ PMWI_Plugin::getInstance();
707
+ }
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Import Products from any XML or CSV to WooCommerce ===
2
  Contributors: soflyy, wpallimport
3
  Requires at least: 4.1
4
- Tested up to: 4.9.6
5
- Stable tag: 1.3.9
6
  License: GPLv2 or later
7
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
8
  Tags: woocommerce xml import, woocommerce csv import, woocommerce, import, xml, csv, wp all import, csv import, import csv, xml import, import xml, woocommerce csv importer, woocommerce xml importer, csv importer, csv import suite
@@ -83,6 +83,11 @@ The WooCommerce add-on will appear in the Step 4 of WP All Import.
83
 
84
  == Changelog ==
85
 
 
 
 
 
 
86
  = 1.3.9 =
87
  bug fix: do not execute product import code when importing other post types
88
 
1
  === Import Products from any XML or CSV to WooCommerce ===
2
  Contributors: soflyy, wpallimport
3
  Requires at least: 4.1
4
+ Tested up to: 5.1
5
+ Stable tag: 1.4.0
6
  License: GPLv2 or later
7
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
8
  Tags: woocommerce xml import, woocommerce csv import, woocommerce, import, xml, csv, wp all import, csv import, import csv, xml import, import xml, woocommerce csv importer, woocommerce xml importer, csv importer, csv import suite
83
 
84
  == Changelog ==
85
 
86
+ = 1.4.0 =
87
+ improvement: notice on plugin activation when WooCoomerce Add-On Pro installed
88
+ improvement: match cross-sell products by title
89
+ bug fix: shipping class not imported properly in some cases
90
+
91
  = 1.3.9 =
92
  bug fix: do not execute product import code when importing other post types
93
 
views/admin/import/_tabs/_linked_product.php CHANGED
@@ -36,10 +36,6 @@
36
 
37
  if ( $grouped_products ) {
38
  foreach ( $grouped_products as $product ) {
39
-
40
- if ( $product->ID == $post->ID )
41
- continue;
42
-
43
  $post_parents[ $product->ID ] = $product->post_title;
44
  }
45
  }
36
 
37
  if ( $grouped_products ) {
38
  foreach ( $grouped_products as $product ) {
 
 
 
 
39
  $post_parents[ $product->ID ] = $product->post_title;
40
  }
41
  }