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

Version Description

  • fixed automatic fixing of improperly formatted prices
  • fixed php notices
  • updated css for compatibility with wocommerce 2.1
  • added download type option
  • added file names option
Download this release

Release Info

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

Code changes from version 1.1.3 to 1.1.4

actions/admin_notices.php CHANGED
@@ -31,7 +31,7 @@ function pmwi_admin_notices() {
31
 
32
  }
33
 
34
- if ( class_exists( 'PMXI_Plugin' ) and ( version_compare(PMXI_VERSION, '3.3.3') <= 0 and PMXI_EDITION == 'paid' or version_compare(PMXI_VERSION, '3.1.0') < 0 and PMXI_EDITION == 'free') ) {
35
  ?>
36
  <div class="error"><p>
37
  <?php printf(
31
 
32
  }
33
 
34
+ if ( class_exists( 'PMXI_Plugin' ) and ( version_compare(PMXI_VERSION, '3.3.6') <= 0 and PMXI_EDITION == 'paid' or version_compare(PMXI_VERSION, '3.1.1') <= 0 and PMXI_EDITION == 'free') ) {
35
  ?>
36
  <div class="error"><p>
37
  <?php printf(
actions/pmxi_do_not_update_existing.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function pmwi_pmxi_do_not_update_existing($post_to_update_id, $import_id, $iteration){
3
+ $children = get_posts( array(
4
+ 'post_parent' => $post_to_update_id,
5
+ 'posts_per_page'=> -1,
6
+ 'post_type' => 'product_variation',
7
+ 'fields' => 'ids',
8
+ 'post_status' => 'publish'
9
+ ) );
10
+
11
+ if ( $children ) {
12
+ $postRecord = new PMXI_Post_Record();
13
+ foreach ( $children as $child ) {
14
+ $postRecord->clear();
15
+ $postRecord->getBy(array(
16
+ 'post_id' => $child,
17
+ 'import_id' => $import_id
18
+ ));
19
+ if ( ! $postRecord->isEmpty() ) $postRecord->set(array('iteration' => $iteration))->update();
20
+ }
21
+ }
22
+
23
+ }
24
+ ?>
actions/pmxi_reimport.php CHANGED
@@ -19,6 +19,11 @@ function pmwi_pmxi_reimport($entry, $post){
19
 
20
  ?>
21
  <div class="input">
 
 
 
 
 
22
  <input type="hidden" name="attributes_list" value="0" />
23
  <input type="hidden" name="is_update_attributes" value="0" />
24
  <input type="checkbox" id="is_update_attributes_<?php echo $entry; ?>" name="is_update_attributes" value="1" <?php echo $post['is_update_attributes'] ? 'checked="checked"': '' ?> class="switcher"/>
19
 
20
  ?>
21
  <div class="input">
22
+ <input type="hidden" name="is_update_product_type" value="0" />
23
+ <input type="checkbox" id="is_update_product_type_<?php echo $entry; ?>" name="is_update_product_type" value="1" <?php echo $post['is_update_product_type'] ? 'checked="checked"': '' ?> class="switcher"/>
24
+ <label for="is_update_product_type_<?php echo $entry; ?>"><?php _e('Product Type', 'pmxi_plugin') ?></label>
25
+ </div>
26
+ <div class="input">
27
  <input type="hidden" name="attributes_list" value="0" />
28
  <input type="hidden" name="is_update_attributes" value="0" />
29
  <input type="checkbox" id="is_update_attributes_<?php echo $entry; ?>" name="is_update_attributes" value="1" <?php echo $post['is_update_attributes'] ? 'checked="checked"': '' ?> class="switcher"/>
actions/wp_loaded.php DELETED
@@ -1,6 +0,0 @@
1
- <?php
2
-
3
- function pmwi_wp_loaded() {
4
-
5
-
6
- }
 
 
 
 
 
 
controllers/admin/import.php CHANGED
@@ -28,7 +28,7 @@ class PMWI_Admin_Import extends PMWI_Controller_Admin {
28
  + $default
29
  );
30
 
31
- $this->data['is_loaded_template'] = PMXI_Plugin::$session->data['pmxi_import']['is_loaded_template'];
32
 
33
  $load_options = $this->input->post('load_template');
34
 
28
  + $default
29
  );
30
 
31
+ $this->data['is_loaded_template'] = (!empty(PMXI_Plugin::$session->data['pmxi_import']) and !empty(PMXI_Plugin::$session->data['pmxi_import']['is_loaded_template'])) ? PMXI_Plugin::$session->data['pmxi_import']['is_loaded_template'] : false;
32
 
33
  $load_options = $this->input->post('load_template');
34
 
filters/pmxi_do_not_update_existing.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
- function pmwi_pmxi_do_not_update_existing($current_post_ids, $post_to_update_id){
3
- $children = get_posts( array(
4
- 'post_parent' => $post_to_update_id,
5
- 'posts_per_page'=> -1,
6
- 'post_type' => 'product_variation',
7
- 'fields' => 'ids',
8
- 'post_status' => 'publish'
9
- ) );
10
-
11
- if ( $children ) {
12
- foreach ( $children as $child ) {
13
- if ( ! in_array($child, $current_post_ids) ) $current_post_ids[] = $child;
14
- }
15
- }
16
- return $current_post_ids;
17
- }
18
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models/import/record.php CHANGED
@@ -8,6 +8,8 @@ class PMWI_Import_Record extends PMWI_Model_Record {
8
  */
9
  public $data = array();
10
 
 
 
11
  /**
12
  * Initialize model instance
13
  * @param array[optional] $data Array of record data to initialize object with
@@ -32,6 +34,8 @@ class PMWI_Import_Record extends PMWI_Model_Record {
32
 
33
  add_filter('user_has_cap', array($this, '_filter_has_cap_unfiltered_html')); kses_init(); // do not perform special filtering for imported content
34
 
 
 
35
  $cxpath = $xpath_prefix . $import->xpath;
36
 
37
  $this->data = array();
@@ -149,6 +153,13 @@ class PMWI_Import_Record extends PMWI_Model_Record {
149
  }
150
  else{
151
  $count and $this->data['product_files'] = array_fill(0, $count, "");
 
 
 
 
 
 
 
152
  }
153
 
154
  if ("" != $import->options['single_product_download_limit']){
@@ -164,6 +175,13 @@ class PMWI_Import_Record extends PMWI_Model_Record {
164
  else{
165
  $count and $this->data['product_download_expiry'] = array_fill(0, $count, "");
166
  }
 
 
 
 
 
 
 
167
 
168
  // Composing product Tax Status
169
  if ($import->options['is_multiple_product_tax_status'] != 'yes' and "" != $import->options['single_product_tax_status']){
@@ -266,11 +284,31 @@ class PMWI_Import_Record extends PMWI_Model_Record {
266
  $count and $this->data['product_cross_sells'] = array_fill(0, $count, "");
267
  }
268
 
269
- if ("" != $import->options['grouping_product']){
270
- $this->data['product_grouping_parent'] = XmlImportParser::factory($xml, $cxpath, $import->options['grouping_product'], $file)->parse($records); $tmp_files[] = $file;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  }
272
  else{
273
- $count and $this->data['product_grouping_parent'] = array_fill(0, $count, "");
274
  }
275
 
276
  if ("" != $import->options['single_product_purchase_note']){
@@ -362,7 +400,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
362
  $attribute_is_visible = array();
363
  $attribute_is_taxonomy = array();
364
  $attribute_create_taxonomy_terms = array();
365
-
366
  if (!empty($import->options['attribute_name'][0])){
367
  foreach ($import->options['attribute_name'] as $j => $attribute_name) { if ($attribute_name == "") continue;
368
  $attribute_keys[$j] = XmlImportParser::factory($xml, $cxpath, $attribute_name, $file)->parse($records); $tmp_files[] = $file;
@@ -370,23 +408,24 @@ class PMWI_Import_Record extends PMWI_Model_Record {
370
  $attribute_in_variation[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['in_variations'][$j], $file)->parse($records); $tmp_files[] = $file;
371
  $attribute_is_visible[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['is_visible'][$j], $file)->parse($records); $tmp_files[] = $file;
372
  $attribute_is_taxonomy[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['is_taxonomy'][$j], $file)->parse($records); $tmp_files[] = $file;
373
- $attribute_create_taxonomy_terms[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['create_taxonomy_in_not_exists'][$j], $file)->parse($records); $tmp_files[] = $file;
374
  }
375
  }
376
-
377
  // serialized attributes for product variations
378
  $this->data['serialized_attributes'] = array();
379
  if (!empty($attribute_keys)){
380
- foreach ($attribute_keys as $j => $attribute_name) {
381
- if (!in_array($attribute_name[0], array_keys($this->data['serialized_attributes']))){
382
- $this->data['serialized_attributes'][$attribute_name[0]] = array(
383
- 'value' => $attribute_values[$j],
384
- 'is_visible' => $attribute_is_visible[$j],
385
- 'in_variation' => $attribute_in_variation[$j],
386
- 'in_taxonomy' => $attribute_is_taxonomy[$j],
387
- 'is_create_taxonomy_terms' => $attribute_create_taxonomy_terms[$j]
388
- );
389
- }
 
390
  }
391
  }
392
 
@@ -420,6 +459,12 @@ class PMWI_Import_Record extends PMWI_Model_Record {
420
 
421
  // Get types
422
  $product_type = empty( $product_types[$i] ) ? 'simple' : sanitize_title( stripslashes( $product_types[$i] ) );
 
 
 
 
 
 
423
  $is_downloadable = $product_downloadable[$i];
424
  $is_virtual = $product_virtual[$i];
425
  $is_featured = $product_featured[$i];
@@ -476,7 +521,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
476
  }
477
  elseif ( $new_sku == '' and ! $import->options['disable_auto_sku_generation'] ) {
478
  if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_sku')){
479
- $unique_keys = XmlImportParser::factory($xml, $cxpath, $import->options['unique_key'], $file)->parse($records); $tmp_files[] = $file;
480
  foreach ($tmp_files as $file) { // remove all temporary files created
481
  unlink($file);
482
  }
@@ -510,11 +555,19 @@ class PMWI_Import_Record extends PMWI_Model_Record {
510
 
511
  if ( $import->options['update_all_data'] == "yes" or ( $import->options['update_all_data'] == "no" and $import->options['is_update_attributes']) or empty($articleData['ID'])): // Update Product Attributes
512
 
 
 
513
  if ( !empty($serialized_attributes) ) {
514
 
515
- $attribute_position = 0; $is_update_attributes = true;
516
 
517
- foreach ($serialized_attributes as $attr_name => $attr_data) { $attr_name = strtolower($attr_name);
 
 
 
 
 
 
518
 
519
  $is_visible = intval( $attr_data['is_visible'][$i] );
520
  $is_variation = intval( $attr_data['in_variation'][$i] );
@@ -551,68 +604,15 @@ class PMWI_Import_Record extends PMWI_Model_Record {
551
  $values = array_map( 'stripslashes', array_map( 'strip_tags', explode( '|', $attr_data['value'][$i] ) ) );
552
 
553
  // Remove empty items in the array
554
- $values = array_filter( $values, array($this, "filtering") );
555
-
556
- if ( ! taxonomy_exists( $woocommerce->attribute_taxonomy_name( $attr_name ) ) and intval($attr_data['is_create_taxonomy_terms'][$i])) {
557
-
558
- // Grab the submitted data
559
- $attribute_name = ( isset( $attr_name ) ) ? pmwi_sanitize_taxonomy_name( stripslashes( (string) $attr_name ) ) : '';
560
- $attribute_label = ucwords( stripslashes( (string) $attr_name ));
561
- $attribute_type = 'select';
562
- $attribute_orderby = 'menu_order';
563
-
564
- $reserved_terms = array(
565
- 'attachment', 'attachment_id', 'author', 'author_name', 'calendar', 'cat', 'category', 'category__and',
566
- 'category__in', 'category__not_in', 'category_name', 'comments_per_page', 'comments_popup', 'cpage', 'day',
567
- 'debug', 'error', 'exact', 'feed', 'hour', 'link_category', 'm', 'minute', 'monthnum', 'more', 'name',
568
- 'nav_menu', 'nopaging', 'offset', 'order', 'orderby', 'p', 'page', 'page_id', 'paged', 'pagename', 'pb', 'perm',
569
- 'post', 'post__in', 'post__not_in', 'post_format', 'post_mime_type', 'post_status', 'post_tag', 'post_type',
570
- 'posts', 'posts_per_archive_page', 'posts_per_page', 'preview', 'robots', 's', 'search', 'second', 'sentence',
571
- 'showposts', 'static', 'subpost', 'subpost_id', 'tag', 'tag__and', 'tag__in', 'tag__not_in', 'tag_id',
572
- 'tag_slug__and', 'tag_slug__in', 'taxonomy', 'tb', 'term', 'w', 'withcomments', 'withoutcomments', 'year',
573
- );
574
-
575
- if ( in_array( $attribute_name, $reserved_terms ) ) {
576
- $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Slug “%s” is not allowed because it is a reserved term. Change it, please.', 'pmxi_plugin'), sanitize_title( $attribute_name )));
577
- }
578
- else{
579
- $this->wpdb->insert(
580
- $this->wpdb->prefix . 'woocommerce_attribute_taxonomies',
581
- array(
582
- 'attribute_label' => $attribute_label,
583
- 'attribute_name' => $attribute_name,
584
- 'attribute_type' => $attribute_type,
585
- 'attribute_orderby' => $attribute_orderby,
586
- )
587
- );
588
-
589
- $logger and call_user_func($logger, sprintf(__('<b>CREATED</b>: Taxonomy attribute “%s” have been successfully created.', 'pmxi_plugin'), $attribute_label));
590
-
591
- // Register the taxonomy now so that the import works!
592
- $domain = $woocommerce->attribute_taxonomy_name( $attr_name );
593
- register_taxonomy( $domain,
594
- apply_filters( 'woocommerce_taxonomy_objects_' . $domain, array('product') ),
595
- apply_filters( 'woocommerce_taxonomy_args_' . $domain, array(
596
- 'hierarchical' => true,
597
- 'show_ui' => false,
598
- 'query_var' => true,
599
- 'rewrite' => false,
600
- ) )
601
- );
602
-
603
- delete_transient( 'wc_attribute_taxonomies' );
604
- $attribute_taxonomies = $this->wpdb->get_results( "SELECT * FROM " . $this->wpdb->prefix . "woocommerce_attribute_taxonomies" );
605
- set_transient( 'wc_attribute_taxonomies', $attribute_taxonomies );
606
- apply_filters( 'woocommerce_attribute_taxonomies', $attribute_taxonomies );
607
- }
608
-
609
- }
610
-
611
- if ( ! empty($values) and taxonomy_exists( $woocommerce->attribute_taxonomy_name( $attr_name ) )){
612
 
613
  $attr_values = array();
614
 
615
- $terms = get_terms( $woocommerce->attribute_taxonomy_name( $attr_name ), array('hide_empty' => false));
616
 
617
  if ( ! is_wp_error($terms) ){
618
 
@@ -630,10 +630,10 @@ class PMWI_Import_Record extends PMWI_Model_Record {
630
  if ( ! $term_founded and intval($attr_data['is_create_taxonomy_terms'][$i]) ){
631
  $term = wp_insert_term(
632
  $value, // the term
633
- $woocommerce->attribute_taxonomy_name( $attr_name ) // the taxonomy
634
  );
635
  if ( ! is_wp_error($term) ){
636
- $term = get_term_by( 'id', $term['term_id'], $woocommerce->attribute_taxonomy_name( $attr_name ));
637
  $attr_values[] = $term->slug;
638
  }
639
 
@@ -653,13 +653,13 @@ class PMWI_Import_Record extends PMWI_Model_Record {
653
  }
654
 
655
  // Update post terms
656
- if ( taxonomy_exists( $woocommerce->attribute_taxonomy_name( $attr_name ) ))
657
- wp_set_object_terms( $pid, $values, $woocommerce->attribute_taxonomy_name( $attr_name ) );
658
 
659
  if ( !empty($values) ) {
660
  // Add attribute to array, but don't set values
661
- $attributes[ $woocommerce->attribute_taxonomy_name( $attr_name ) ] = array(
662
- 'name' => $woocommerce->attribute_taxonomy_name( $attr_name ),
663
  'value' => '',
664
  'position' => $attribute_position,
665
  'is_visible' => $is_visible,
@@ -671,8 +671,8 @@ class PMWI_Import_Record extends PMWI_Model_Record {
671
 
672
  } else {
673
 
674
- if ( taxonomy_exists( $woocommerce->attribute_taxonomy_name( $attr_name ) ))
675
- wp_set_object_terms( $pid, NULL, $woocommerce->attribute_taxonomy_name( $attr_name ) );
676
 
677
  if (!empty($attr_data['value'][$i])){
678
 
@@ -746,6 +746,35 @@ class PMWI_Import_Record extends PMWI_Model_Record {
746
  }
747
  }
748
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
749
  // Update parent if grouped so price sorting works and stays in sync with the cheapest child
750
  if ( $product_type == 'grouped' || ( "" != $product_grouping_parent[$i] and absint($product_grouping_parent[$i]) > 0)) {
751
 
@@ -777,7 +806,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
777
  }
778
 
779
  // Clear cache/transients
780
- $woocommerce->clear_product_transients( $clear_id );
781
  }
782
  }
783
  }
@@ -790,7 +819,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
790
  }
791
 
792
  // Stock Data
793
- if ( $product_manage_stock[$i] == 'yes' ) {
794
 
795
  if ( $product_type == 'grouped' ) {
796
 
@@ -903,28 +932,84 @@ class PMWI_Import_Record extends PMWI_Model_Record {
903
  $_file_paths = array();
904
 
905
  $file_paths = explode( $import->options['product_files_delim'] , $product_files[$i] );
 
906
 
907
- foreach ( $file_paths as $file_path ) {
908
  $file_path = trim( $file_path );
909
- $_file_paths[ md5( $file_path ) ] = $file_path;
910
- }
911
 
912
- // grant permission to any newly added files on any existing orders for this product
913
- //do_action( 'woocommerce_process_product_file_download_paths', $pid, 0, $_file_paths );
914
-
915
- if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_file_paths')) update_post_meta( $pid, '_file_paths', $_file_paths );
916
  }
917
  if ( isset( $product_download_limit[$i] ) )
918
  if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_download_limit')) update_post_meta( $pid, '_download_limit', esc_attr( $_download_limit ) );
919
  if ( isset( $product_download_expiry[$i] ) )
920
  if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_download_expiry')) update_post_meta( $pid, '_download_expiry', esc_attr( $_download_expiry ) );
921
- }
922
-
923
- // Clear cache/transients
924
- $woocommerce->clear_product_transients( $pid );
925
 
926
  }
927
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
928
 
929
  function pmwi_link_all_variations($product_id, $options = array()) {
930
 
@@ -998,7 +1083,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
998
  if ( in_array( $variation, $available_variations ) )
999
  continue;
1000
 
1001
- $variation_id = ($options['is_fast_mode']) ? pmxi_insert_post($variation_post_data) : wp_insert_post( $variation_post_data );
1002
 
1003
  update_post_meta( $variation_id, '_regular_price', get_post_meta( $post_id, '_regular_price', true ) );
1004
  update_post_meta( $variation_id, '_sale_price', get_post_meta( $post_id, '_sale_price', true ) );
@@ -1019,7 +1104,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
1019
 
1020
  }
1021
 
1022
- $woocommerce->clear_product_transients( $post_id );
1023
 
1024
  return $added;
1025
  }
@@ -1084,7 +1169,7 @@ class PMWI_Import_Record extends PMWI_Model_Record {
1084
  {
1085
  $caps['unfiltered_html'] = true;
1086
  return $caps;
1087
- }
1088
 
1089
  function duplicate_post_copy_post_meta_info($new_id, $post) {
1090
  $post_meta_keys = get_post_custom_keys($post->ID);
@@ -1102,7 +1187,9 @@ class PMWI_Import_Record extends PMWI_Model_Record {
1102
  }
1103
 
1104
  function auto_cloak_links($import, &$url){
1105
- $url = trim($url);
 
 
1106
  // cloak urls with `WP Wizard Cloak` if corresponding option is set
1107
  if ( ! empty($import->options['is_cloak']) and class_exists('PMLC_Plugin')) {
1108
  if (preg_match('%^\w+://%i', $url)) { // mask only links having protocol
@@ -1261,18 +1348,12 @@ class PMWI_Import_Record extends PMWI_Model_Record {
1261
 
1262
  function prepare_price( $price ){
1263
 
1264
- $price = preg_replace("/[^0-9\.,]/","", $price);
1265
 
1266
- if ( preg_match("%^[0-9,]+(\.[0-9]{1,}){1}$%", $price)) {
1267
- $price = str_replace(",", "", $price);
1268
- }
1269
- elseif ( preg_match("%^[0-9\.]+(\,[0-9]{1,}){1}$%", $price)) {
1270
- $price = str_replace(",", ".", str_replace(".", "", $price));
1271
- }
1272
- else{
1273
- $price = str_replace(",", ".", $price);
1274
- }
1275
 
1276
- return number_format($price, 2, '.', '');
 
 
1277
  }
1278
  }
8
  */
9
  public $data = array();
10
 
11
+ public $options = array();
12
+
13
  /**
14
  * Initialize model instance
15
  * @param array[optional] $data Array of record data to initialize object with
34
 
35
  add_filter('user_has_cap', array($this, '_filter_has_cap_unfiltered_html')); kses_init(); // do not perform special filtering for imported content
36
 
37
+ $this->options = $import->options;
38
+
39
  $cxpath = $xpath_prefix . $import->xpath;
40
 
41
  $this->data = array();
153
  }
154
  else{
155
  $count and $this->data['product_files'] = array_fill(0, $count, "");
156
+ }
157
+
158
+ if ("" != $import->options['single_product_files_names']){
159
+ $this->data['product_files_names'] = XmlImportParser::factory($xml, $cxpath, $import->options['single_product_files_names'], $file)->parse($records); $tmp_files[] = $file;
160
+ }
161
+ else{
162
+ $count and $this->data['product_files_names'] = array_fill(0, $count, "");
163
  }
164
 
165
  if ("" != $import->options['single_product_download_limit']){
175
  else{
176
  $count and $this->data['product_download_expiry'] = array_fill(0, $count, "");
177
  }
178
+
179
+ if ("" != $import->options['single_product_download_type']){
180
+ $this->data['product_download_type'] = XmlImportParser::factory($xml, $cxpath, $import->options['single_product_download_type'], $file)->parse($records); $tmp_files[] = $file;
181
+ }
182
+ else{
183
+ $count and $this->data['product_download_type'] = array_fill(0, $count, "");
184
+ }
185
 
186
  // Composing product Tax Status
187
  if ($import->options['is_multiple_product_tax_status'] != 'yes' and "" != $import->options['single_product_tax_status']){
284
  $count and $this->data['product_cross_sells'] = array_fill(0, $count, "");
285
  }
286
 
287
+ if ($import->options['is_multiple_grouping_product'] != 'yes'){
288
+
289
+ if ($import->options['grouping_indicator'] == 'xpath'){
290
+
291
+ if ("" != $import->options['single_grouping_product']){
292
+ $this->data['product_grouping_parent'] = XmlImportParser::factory($xml, $cxpath, $import->options['single_grouping_product'], $file)->parse($records); $tmp_files[] = $file;
293
+ }
294
+ else{
295
+ $count and $this->data['product_grouping_parent'] = array_fill(0, $count, $import->options['multiple_grouping_product']);
296
+ }
297
+
298
+ }
299
+ else{
300
+ if ("" != $import->options['custom_grouping_indicator_name'] and "" != $import->options['custom_grouping_indicator_value'] ){
301
+ $this->data['custom_grouping_indicator_name'] = XmlImportParser::factory($xml, $cxpath, $import->options['custom_grouping_indicator_name'], $file)->parse($records); $tmp_files[] = $file;
302
+ $this->data['custom_grouping_indicator_value'] = XmlImportParser::factory($xml, $cxpath, $import->options['custom_grouping_indicator_value'], $file)->parse($records); $tmp_files[] = $file;
303
+ }
304
+ else{
305
+ $count and $this->data['custom_grouping_indicator_name'] = array_fill(0, $count, "");
306
+ $count and $this->data['custom_grouping_indicator_value'] = array_fill(0, $count, "");
307
+ }
308
+ }
309
  }
310
  else{
311
+ $count and $this->data['product_grouping_parent'] = array_fill(0, $count, $import->options['multiple_grouping_product']);
312
  }
313
 
314
  if ("" != $import->options['single_product_purchase_note']){
400
  $attribute_is_visible = array();
401
  $attribute_is_taxonomy = array();
402
  $attribute_create_taxonomy_terms = array();
403
+
404
  if (!empty($import->options['attribute_name'][0])){
405
  foreach ($import->options['attribute_name'] as $j => $attribute_name) { if ($attribute_name == "") continue;
406
  $attribute_keys[$j] = XmlImportParser::factory($xml, $cxpath, $attribute_name, $file)->parse($records); $tmp_files[] = $file;
408
  $attribute_in_variation[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['in_variations'][$j], $file)->parse($records); $tmp_files[] = $file;
409
  $attribute_is_visible[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['is_visible'][$j], $file)->parse($records); $tmp_files[] = $file;
410
  $attribute_is_taxonomy[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['is_taxonomy'][$j], $file)->parse($records); $tmp_files[] = $file;
411
+ $attribute_create_taxonomy_terms[$j] = XmlImportParser::factory($xml, $cxpath, $import->options['create_taxonomy_in_not_exists'][$j], $file)->parse($records); $tmp_files[] = $file;
412
  }
413
  }
414
+
415
  // serialized attributes for product variations
416
  $this->data['serialized_attributes'] = array();
417
  if (!empty($attribute_keys)){
418
+ foreach ($attribute_keys as $j => $attribute_name) {
419
+
420
+ $this->data['serialized_attributes'][] = array(
421
+ 'names' => $attribute_name,
422
+ 'value' => $attribute_values[$j],
423
+ 'is_visible' => $attribute_is_visible[$j],
424
+ 'in_variation' => $attribute_in_variation[$j],
425
+ 'in_taxonomy' => $attribute_is_taxonomy[$j],
426
+ 'is_create_taxonomy_terms' => $attribute_create_taxonomy_terms[$j]
427
+ );
428
+
429
  }
430
  }
431
 
459
 
460
  // Get types
461
  $product_type = empty( $product_types[$i] ) ? 'simple' : sanitize_title( stripslashes( $product_types[$i] ) );
462
+
463
+ if ( ! $import->options['is_update_product_type'] and ! empty($articleData['ID']) ){
464
+ $product = get_product($pid);
465
+ $product_type = $product->product_type;
466
+ }
467
+
468
  $is_downloadable = $product_downloadable[$i];
469
  $is_virtual = $product_virtual[$i];
470
  $is_featured = $product_featured[$i];
521
  }
522
  elseif ( $new_sku == '' and ! $import->options['disable_auto_sku_generation'] ) {
523
  if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_sku')){
524
+ $unique_keys = XmlImportParser::factory($xml, $cxpath, $import->options['unique_key'], $file)->parse(); $tmp_files[] = $file;
525
  foreach ($tmp_files as $file) { // remove all temporary files created
526
  unlink($file);
527
  }
555
 
556
  if ( $import->options['update_all_data'] == "yes" or ( $import->options['update_all_data'] == "no" and $import->options['is_update_attributes']) or empty($articleData['ID'])): // Update Product Attributes
557
 
558
+ $is_update_attributes = true;
559
+
560
  if ( !empty($serialized_attributes) ) {
561
 
562
+ $attribute_position = 0;
563
 
564
+ $attr_names = array();
565
+
566
+ foreach ($serialized_attributes as $anum => $attr_data) { $attr_name = strtolower($attr_data['names'][$i]);
567
+
568
+ if (empty($attr_name) or in_array($attr_name, $attr_names)) continue;
569
+
570
+ $attr_names[] = $attr_name;
571
 
572
  $is_visible = intval( $attr_data['is_visible'][$i] );
573
  $is_variation = intval( $attr_data['in_variation'][$i] );
604
  $values = array_map( 'stripslashes', array_map( 'strip_tags', explode( '|', $attr_data['value'][$i] ) ) );
605
 
606
  // Remove empty items in the array
607
+ $values = array_filter( $values, array($this, "filtering") );
608
+
609
+ if (intval($attr_data['is_create_taxonomy_terms'][$i])) $this->create_taxonomy($attr_name, $logger);
610
+
611
+ if ( ! empty($values) and taxonomy_exists( wc_attribute_taxonomy_name( $attr_name ) )){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
 
613
  $attr_values = array();
614
 
615
+ $terms = get_terms( wc_attribute_taxonomy_name( $attr_name ), array('hide_empty' => false));
616
 
617
  if ( ! is_wp_error($terms) ){
618
 
630
  if ( ! $term_founded and intval($attr_data['is_create_taxonomy_terms'][$i]) ){
631
  $term = wp_insert_term(
632
  $value, // the term
633
+ wc_attribute_taxonomy_name( $attr_name ) // the taxonomy
634
  );
635
  if ( ! is_wp_error($term) ){
636
+ $term = get_term_by( 'id', $term['term_id'], wc_attribute_taxonomy_name( $attr_name ));
637
  $attr_values[] = $term->slug;
638
  }
639
 
653
  }
654
 
655
  // Update post terms
656
+ if ( taxonomy_exists( wc_attribute_taxonomy_name( $attr_name ) ))
657
+ wp_set_object_terms( $pid, $values, wc_attribute_taxonomy_name( $attr_name ) );
658
 
659
  if ( !empty($values) ) {
660
  // Add attribute to array, but don't set values
661
+ $attributes[ wc_attribute_taxonomy_name( $attr_name ) ] = array(
662
+ 'name' => wc_attribute_taxonomy_name( $attr_name ),
663
  'value' => '',
664
  'position' => $attribute_position,
665
  'is_visible' => $is_visible,
671
 
672
  } else {
673
 
674
+ if ( taxonomy_exists( wc_attribute_taxonomy_name( $attr_name ) ))
675
+ wp_set_object_terms( $pid, NULL, wc_attribute_taxonomy_name( $attr_name ) );
676
 
677
  if (!empty($attr_data['value'][$i])){
678
 
746
  }
747
  }
748
 
749
+ if ($import->options['is_multiple_grouping_product'] != 'yes'){
750
+ if ($import->options['grouping_indicator'] == 'xpath' and ! is_numeric($product_grouping_parent[$i])){
751
+ $dpost = pmxi_findDuplicates(array(
752
+ 'post_type' => 'product',
753
+ 'ID' => $pid,
754
+ 'post_parent' => $articleData['post_parent'],
755
+ 'post_title' => $product_grouping_parent[$i]
756
+ ));
757
+ if (!empty($dpost))
758
+ $product_grouping_parent[$i] = $dpost[0];
759
+ else
760
+ $product_grouping_parent[$i] = 0;
761
+ }
762
+ elseif ($import->options['grouping_indicator'] != 'xpath'){
763
+ $dpost = pmxi_findDuplicates($articleData, $custom_grouping_indicator_name[$i], $custom_grouping_indicator_value[$i], 'custom field');
764
+ if (!empty($dpost))
765
+ $product_grouping_parent[$i] = array_shift($dpost);
766
+ else
767
+ $product_grouping_parent[$i] = 0;
768
+ }
769
+ }
770
+
771
+ if ( "" != $product_grouping_parent[$i] and absint($product_grouping_parent[$i]) > 0){
772
+ wp_update_post(array(
773
+ 'ID' => $pid,
774
+ 'post_parent' => absint( $product_grouping_parent[$i] )
775
+ ));
776
+ }
777
+
778
  // Update parent if grouped so price sorting works and stays in sync with the cheapest child
779
  if ( $product_type == 'grouped' || ( "" != $product_grouping_parent[$i] and absint($product_grouping_parent[$i]) > 0)) {
780
 
806
  }
807
 
808
  // Clear cache/transients
809
+ //$woocommerce->clear_product_transients( $clear_id );
810
  }
811
  }
812
  }
819
  }
820
 
821
  // Stock Data
822
+ if ( strtolower($product_manage_stock[$i]) == 'yes' ) {
823
 
824
  if ( $product_type == 'grouped' ) {
825
 
932
  $_file_paths = array();
933
 
934
  $file_paths = explode( $import->options['product_files_delim'] , $product_files[$i] );
935
+ $file_names = explode( $import->options['product_files_names_delim'] , $product_files_names[$i] );
936
 
937
+ foreach ( $file_paths as $fn => $file_path ) {
938
  $file_path = trim( $file_path );
939
+ $_file_paths[ md5( $file_path ) ] = array('name' => ((!empty($file_names[$fn])) ? $file_names[$fn] : basename($file_path)), 'file' => $file_path);
940
+ }
941
 
942
+ if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_downloadable_files')) update_post_meta( $pid, '_downloadable_files', $_file_paths );
 
 
 
943
  }
944
  if ( isset( $product_download_limit[$i] ) )
945
  if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_download_limit')) update_post_meta( $pid, '_download_limit', esc_attr( $_download_limit ) );
946
  if ( isset( $product_download_expiry[$i] ) )
947
  if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_download_expiry')) update_post_meta( $pid, '_download_expiry', esc_attr( $_download_expiry ) );
948
+ if ( isset( $product_download_type[$i] ) )
949
+ if (empty($articleData['ID']) or $this->is_update_custom_field($existing_meta_keys, $import->options, '_download_type')) update_post_meta( $pid, '_download_type', esc_attr( $product_download_type[$i] ) );
950
+ }
 
951
 
952
  }
953
 
954
+ function create_taxonomy($attr_name, $logger){
955
+
956
+ global $woocommerce;
957
+
958
+ if ( ! taxonomy_exists( wc_attribute_taxonomy_name( $attr_name ) ) ) {
959
+
960
+ // Grab the submitted data
961
+ $attribute_name = ( isset( $attr_name ) ) ? pmwi_sanitize_taxonomy_name( stripslashes( (string) $attr_name ) ) : '';
962
+ $attribute_label = ucwords( stripslashes( (string) $attr_name ));
963
+ $attribute_type = 'select';
964
+ $attribute_orderby = 'menu_order';
965
+
966
+ $reserved_terms = array(
967
+ 'attachment', 'attachment_id', 'author', 'author_name', 'calendar', 'cat', 'category', 'category__and',
968
+ 'category__in', 'category__not_in', 'category_name', 'comments_per_page', 'comments_popup', 'cpage', 'day',
969
+ 'debug', 'error', 'exact', 'feed', 'hour', 'link_category', 'm', 'minute', 'monthnum', 'more', 'name',
970
+ 'nav_menu', 'nopaging', 'offset', 'order', 'orderby', 'p', 'page', 'page_id', 'paged', 'pagename', 'pb', 'perm',
971
+ 'post', 'post__in', 'post__not_in', 'post_format', 'post_mime_type', 'post_status', 'post_tag', 'post_type',
972
+ 'posts', 'posts_per_archive_page', 'posts_per_page', 'preview', 'robots', 's', 'search', 'second', 'sentence',
973
+ 'showposts', 'static', 'subpost', 'subpost_id', 'tag', 'tag__and', 'tag__in', 'tag__not_in', 'tag_id',
974
+ 'tag_slug__and', 'tag_slug__in', 'taxonomy', 'tb', 'term', 'type', 'w', 'withcomments', 'withoutcomments', 'year',
975
+ );
976
+
977
+ if ( in_array( $attribute_name, $reserved_terms ) ) {
978
+ $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Slug “%s” is not allowed because it is a reserved term. Change it, please.', 'pmxi_plugin'), sanitize_title( $attribute_name )));
979
+ }
980
+ else{
981
+ $this->wpdb->insert(
982
+ $this->wpdb->prefix . 'woocommerce_attribute_taxonomies',
983
+ array(
984
+ 'attribute_label' => $attribute_label,
985
+ 'attribute_name' => $attribute_name,
986
+ 'attribute_type' => $attribute_type,
987
+ 'attribute_orderby' => $attribute_orderby,
988
+ )
989
+ );
990
+
991
+ $logger and call_user_func($logger, sprintf(__('<b>CREATED</b>: Taxonomy attribute “%s” have been successfully created.', 'pmxi_plugin'), sanitize_title( $attribute_name )));
992
+
993
+ // Register the taxonomy now so that the import works!
994
+ $domain = wc_attribute_taxonomy_name( $attr_name );
995
+ register_taxonomy( $domain,
996
+ apply_filters( 'woocommerce_taxonomy_objects_' . $domain, array('product') ),
997
+ apply_filters( 'woocommerce_taxonomy_args_' . $domain, array(
998
+ 'hierarchical' => true,
999
+ 'show_ui' => false,
1000
+ 'query_var' => true,
1001
+ 'rewrite' => false,
1002
+ ) )
1003
+ );
1004
+
1005
+ delete_transient( 'wc_attribute_taxonomies' );
1006
+ $attribute_taxonomies = $this->wpdb->get_results( "SELECT * FROM " . $this->wpdb->prefix . "woocommerce_attribute_taxonomies" );
1007
+ set_transient( 'wc_attribute_taxonomies', $attribute_taxonomies );
1008
+ apply_filters( 'woocommerce_attribute_taxonomies', $attribute_taxonomies );
1009
+ }
1010
+
1011
+ }
1012
+ }
1013
 
1014
  function pmwi_link_all_variations($product_id, $options = array()) {
1015
 
1083
  if ( in_array( $variation, $available_variations ) )
1084
  continue;
1085
 
1086
+ $variation_id = (!empty($options['is_fast_mode'])) ? pmxi_insert_post($variation_post_data) : wp_insert_post( $variation_post_data );
1087
 
1088
  update_post_meta( $variation_id, '_regular_price', get_post_meta( $post_id, '_regular_price', true ) );
1089
  update_post_meta( $variation_id, '_sale_price', get_post_meta( $post_id, '_sale_price', true ) );
1104
 
1105
  }
1106
 
1107
+ //$woocommerce->clear_product_transients( $post_id );
1108
 
1109
  return $added;
1110
  }
1169
  {
1170
  $caps['unfiltered_html'] = true;
1171
  return $caps;
1172
+ }
1173
 
1174
  function duplicate_post_copy_post_meta_info($new_id, $post) {
1175
  $post_meta_keys = get_post_custom_keys($post->ID);
1187
  }
1188
 
1189
  function auto_cloak_links($import, &$url){
1190
+
1191
+ $url = apply_filters('pmwi_cloak_affiliate_url', trim($url), $import->id);
1192
+
1193
  // cloak urls with `WP Wizard Cloak` if corresponding option is set
1194
  if ( ! empty($import->options['is_cloak']) and class_exists('PMLC_Plugin')) {
1195
  if (preg_match('%^\w+://%i', $url)) { // mask only links having protocol
1348
 
1349
  function prepare_price( $price ){
1350
 
1351
+ if ($this->options['disable_prepare_price']) return apply_filters('pmxi_price', $price);
1352
 
1353
+ $price = str_replace(",", ".", preg_replace("/[^0-9\.,]/","", $price));
 
 
 
 
 
 
 
 
1354
 
1355
+ $price = str_replace(",", ".", str_replace(".", "", preg_replace("%\.([0-9]){1,2}?$%", ",$0", $price)));
1356
+
1357
+ return ("" != $price) ? apply_filters('pmxi_price', number_format( (double) $price, 2, '.', '')) : "";
1358
  }
1359
  }
plugin.php CHANGED
@@ -3,7 +3,7 @@
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.1.3
7
  Author: Soflyy
8
  */
9
  /**
@@ -24,7 +24,7 @@ define('PMWI_FREE_ROOT_URL', rtrim(plugin_dir_url(__FILE__), '/'));
24
  */
25
  define('PMWI_PREFIX', 'pmwi_');
26
 
27
- define('PMWI_FREE_VERSION', '1.1.3');
28
 
29
  define('PMWI_EDITION', 'free');
30
 
@@ -212,6 +212,7 @@ final class PMWI_Plugin {
212
  // register admin page pre-dispatcher
213
  add_action('admin_init', array($this, '__adminInit'));
214
 
 
215
  }
216
 
217
  /**
@@ -222,7 +223,7 @@ final class PMWI_Plugin {
222
  $page = strtolower($input->getpost('page', ''));
223
  if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
224
  $this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
225
- }
226
  }
227
 
228
  /**
@@ -414,8 +415,10 @@ final class PMWI_Plugin {
414
  'single_product_regular_price' => '',
415
  'single_product_sale_price' => '',
416
  'single_product_files' => '',
 
417
  'single_product_download_limit' => '',
418
  'single_product_download_expiry' => '',
 
419
  'is_multiple_product_tax_status' => 'yes',
420
  'multiple_product_tax_status' => 'none',
421
  'single_product_tax_status' => '',
@@ -438,6 +441,9 @@ final class PMWI_Plugin {
438
  'is_multiple_product_shipping_class' => 'yes',
439
  'multiple_product_shipping_class' => '',
440
  'single_product_shipping_class' => '',
 
 
 
441
  'single_product_up_sells' => '',
442
  'single_product_cross_sells' => '',
443
  'attribute_name' => array(),
@@ -460,8 +466,8 @@ final class PMWI_Plugin {
460
  'is_regular_price_shedule' => 0,
461
  'single_sale_price_dates_from' => 'now',
462
  'single_sale_price_dates_to' => 'now',
463
- 'product_files_delim' => ',',
464
- 'grouping_product' => '',
465
  'matching_parent' => 'auto',
466
  'parent_indicator' => 'custom field',
467
  'custom_parent_indicator_name' => '',
@@ -483,6 +489,7 @@ final class PMWI_Plugin {
483
  'variable_shipping_class' => '',
484
  'variable_tax_class' => '',
485
  'variable_file_paths' => '',
 
486
  'variable_download_limit' => '',
487
  'variable_download_expiry' => '',
488
  'is_variable_product_virtual' => 'no',
@@ -501,6 +508,7 @@ final class PMWI_Plugin {
501
  'variable_is_taxonomy' => array(),
502
  'variable_create_taxonomy_in_not_exists' => array(),
503
  'variable_product_files_delim' => ',',
 
504
  'variable_image' => '',
505
  'variable_sku' => '',
506
  'is_variable_product_enabled' => 'yes',
@@ -511,6 +519,7 @@ final class PMWI_Plugin {
511
  'variable_sale_price_use_parent' => 0,
512
  'variable_sale_dates_use_parent' => 0,
513
  'variable_weight_use_parent' => 0,
 
514
  'single_variable_product_virtual_use_parent' => 0,
515
  'variable_dimensions_use_parent' => 0,
516
  'variable_image_use_parent' => 0,
@@ -526,6 +535,11 @@ final class PMWI_Plugin {
526
  'disable_auto_sku_generation' => 0,
527
  'is_default_attributes' => 1,
528
  'disable_sku_matching' => 1,
 
 
 
 
 
529
 
530
  'is_update_attributes' => 1,
531
  'update_attributes_logic' => 'full_update',
@@ -536,4 +550,5 @@ final class PMWI_Plugin {
536
  }
537
  }
538
 
539
- PMWI_Plugin::getInstance();
 
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.1.4
7
  Author: Soflyy
8
  */
9
  /**
24
  */
25
  define('PMWI_PREFIX', 'pmwi_');
26
 
27
+ define('PMWI_FREE_VERSION', '1.1.4');
28
 
29
  define('PMWI_EDITION', 'free');
30
 
212
  // register admin page pre-dispatcher
213
  add_action('admin_init', array($this, '__adminInit'));
214
 
215
+
216
  }
217
 
218
  /**
223
  $page = strtolower($input->getpost('page', ''));
224
  if (preg_match('%^' . preg_quote(str_replace('_', '-', self::PREFIX), '%') . '([\w-]+)$%', $page)) {
225
  $this->adminDispatcher($page, strtolower($input->getpost('action', 'index')));
226
+ }
227
  }
228
 
229
  /**
415
  'single_product_regular_price' => '',
416
  'single_product_sale_price' => '',
417
  'single_product_files' => '',
418
+ 'single_product_files_names' => '',
419
  'single_product_download_limit' => '',
420
  'single_product_download_expiry' => '',
421
+ 'single_product_download_type' => '',
422
  'is_multiple_product_tax_status' => 'yes',
423
  'multiple_product_tax_status' => 'none',
424
  'single_product_tax_status' => '',
441
  'is_multiple_product_shipping_class' => 'yes',
442
  'multiple_product_shipping_class' => '',
443
  'single_product_shipping_class' => '',
444
+ 'is_multiple_grouping_product' => 'yes',
445
+ 'multiple_grouping_product' => '',
446
+ 'single_grouping_product' => '',
447
  'single_product_up_sells' => '',
448
  'single_product_cross_sells' => '',
449
  'attribute_name' => array(),
466
  'is_regular_price_shedule' => 0,
467
  'single_sale_price_dates_from' => 'now',
468
  'single_sale_price_dates_to' => 'now',
469
+ 'product_files_delim' => ',',
470
+ 'product_files_names_delim' => ',',
471
  'matching_parent' => 'auto',
472
  'parent_indicator' => 'custom field',
473
  'custom_parent_indicator_name' => '',
489
  'variable_shipping_class' => '',
490
  'variable_tax_class' => '',
491
  'variable_file_paths' => '',
492
+ 'variable_file_names' => '',
493
  'variable_download_limit' => '',
494
  'variable_download_expiry' => '',
495
  'is_variable_product_virtual' => 'no',
508
  'variable_is_taxonomy' => array(),
509
  'variable_create_taxonomy_in_not_exists' => array(),
510
  'variable_product_files_delim' => ',',
511
+ 'variable_product_files_names_delim' => ',',
512
  'variable_image' => '',
513
  'variable_sku' => '',
514
  'is_variable_product_enabled' => 'yes',
519
  'variable_sale_price_use_parent' => 0,
520
  'variable_sale_dates_use_parent' => 0,
521
  'variable_weight_use_parent' => 0,
522
+ 'single_variable_product_virtual' => '',
523
  'single_variable_product_virtual_use_parent' => 0,
524
  'variable_dimensions_use_parent' => 0,
525
  'variable_image_use_parent' => 0,
535
  'disable_auto_sku_generation' => 0,
536
  'is_default_attributes' => 1,
537
  'disable_sku_matching' => 1,
538
+ 'disable_prepare_price' => 0,
539
+ 'grouping_indicator' => 'xpath',
540
+ 'custom_grouping_indicator_name' => '',
541
+ 'custom_grouping_indicator_value' => '',
542
+ 'is_update_product_type' => 1,
543
 
544
  'is_update_attributes' => 1,
545
  'update_attributes_logic' => 'full_update',
550
  }
551
  }
552
 
553
+ PMWI_Plugin::getInstance();
554
+
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Import Products from any XML or CSV to WooCommerce ===
2
  Contributors: soflyy
3
  Requires at least: 3.5
4
- Tested up to: 3.8.1
5
- Stable tag: 1.1.3
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
@@ -73,6 +73,13 @@ The WooCommerce add-on will appear in the Step 4 of WP All Import.
73
 
74
  == Changelog ==
75
 
 
 
 
 
 
 
 
76
  = 1.1.3 =
77
  * Fixed price conversation
78
 
@@ -105,6 +112,6 @@ We do not handle support in the WordPress.org community forums.
105
 
106
  We do try to handle support for our free version users at the following e-mail address:
107
 
108
- E-mail: support@soflyy.com
109
 
110
  Support for free version customers is not guaranteed and based on ability. For premium support, [purchase WP All Import and the WooCommerce add-on.](http://www.wpallimport.com/upgrade-to-pro)
1
  === Import Products from any XML or CSV to WooCommerce ===
2
  Contributors: soflyy
3
  Requires at least: 3.5
4
+ Tested up to: 3.8.2
5
+ Stable tag: 1.1.4
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
73
 
74
  == Changelog ==
75
 
76
+ = 1.1.4 =
77
+ * fixed automatic fixing of improperly formatted prices
78
+ * fixed php notices
79
+ * updated css for compatibility with wocommerce 2.1
80
+ * added download type option
81
+ * added file names option
82
+
83
  = 1.1.3 =
84
  * Fixed price conversation
85
 
112
 
113
  We do try to handle support for our free version users at the following e-mail address:
114
 
115
+ E-mail: support@wpallimport.com
116
 
117
  Support for free version customers is not guaranteed and based on ability. For premium support, [purchase WP All Import and the WooCommerce add-on.](http://www.wpallimport.com/upgrade-to-pro)
static/js/admin.js CHANGED
@@ -213,14 +213,10 @@
213
 
214
  var parent_tagno = parseInt($('.tag').find('input[name="tagno"]').val());
215
 
216
- $('#variations_console').load('admin.php?page=pmxi-admin-import&action=evaluate_variations', {xpath: $input.val(), tagno: $variation_tagno, parent_tagno: parent_tagno}, function () {
217
  $input.attr('readonly', false);
218
  $xml.xml('dragable');
219
- if ($('.error').length){
220
- $xml.html('');
221
- $('#close_xml_tree').hide();
222
- }
223
- else $('#close_xml_tree').show();
224
  });
225
  };
226
 
213
 
214
  var parent_tagno = parseInt($('.tag').find('input[name="tagno"]').val());
215
 
216
+ $('#variations_console').load('admin.php?page=pmxi-admin-import&action=evaluate_variations', {xpath: $input.val(), tagno: $variation_tagno, parent_tagno: parent_tagno}, function (data) {
217
  $input.attr('readonly', false);
218
  $xml.xml('dragable');
219
+ $('#close_xml_tree').show();
 
 
 
 
220
  });
221
  };
222
 
views/admin/import/index.php CHANGED
@@ -30,8 +30,14 @@
30
  </div>
31
  </div>
32
  <div style="float:right;">
33
- <label class="show_if_simple" for="_virtual" style="border-right:none;"><?php _e('Virtual','woocommerce');?>: <input type="checkbox" id="_virtual" name="_virtual" <?php echo ($post['_virtual']) ? 'checked="checked"' : ''; ?>></label>
34
- <label class="show_if_simple" for="_downloadable"><?php _e('Downloadable','woocommerce');?>: <input type="checkbox" id="_downloadable" name="_downloadable" <?php echo ($post['_downloadable']) ? 'checked="checked"' : ''; ?>></label>
 
 
 
 
 
 
35
  </div>
36
  </span>
37
  </h3>
@@ -165,6 +171,12 @@
165
  <input type="text" class="small" name="product_files_delim" value="<?php echo esc_attr($post['product_files_delim']) ?>" style="width:5%; text-align:center;"/>
166
  <a href="#help" class="help" title="<?php _e('File paths/URLs, comma separated. The delimiter is used when an XML element contains multiple URLs/paths - i.e. <code>http://files.com/1.doc, http://files.com/2.doc</code>.', 'pmxi_plugin') ?>">?</a>
167
  </p>
 
 
 
 
 
 
168
  <p class="form-field">
169
  <label><?php _e("Download Limit"); ?></label>
170
  <input type="text" class="short" placeholder="Unimited" name="single_product_download_limit" value="<?php echo esc_attr($post['single_product_download_limit']) ?>"/>&nbsp;
@@ -175,6 +187,11 @@
175
  <input type="text" class="short" placeholder="Never" name="single_product_download_expiry" value="<?php echo esc_attr($post['single_product_download_expiry']) ?>"/>&nbsp;
176
  <?php _e( 'Enter the number of days before a download link expires, or leave blank.', 'woocommerce' ) ?>
177
  </p>
 
 
 
 
 
178
  </div>
179
  <div class="options_group show_if_simple show_if_external show_if_variable">
180
  <div class="input">
@@ -455,19 +472,64 @@
455
  }
456
  }
457
  ?>
458
- <p class="form-field">
459
- <label><?php _e("Grouping", "woocommerce"); ?></label>
460
- <select name="grouping_product">
461
- <?php
462
- foreach ($post_parents as $parent_id => $parent_title) {
463
- ?>
464
- <option value="<?php echo $parent_id; ?>" <?php if ($parent_id == $post['grouping_product']):?>selected="selected"<?php endif;?>><?php echo $parent_title;?></option>
465
- <?php
466
- }
467
- ?>
468
- </select>
469
- <a href="#help" class="help" title="<?php _e('Set this option to make this product part of a grouped product.', 'woocommerce'); ?>">?</a>
470
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  </div>
472
  </div><!-- End Product Panel -->
473
 
@@ -914,7 +976,7 @@
914
  <div class="input">
915
  <?php
916
  $classes = get_the_terms( 0, 'product_shipping_class' );
917
- if ( $classes && ! is_wp_error( $classes ) ) $current_shipping_class = current($classes)->term_id; else $current_shipping_class = '';
918
 
919
  $args = array(
920
  'taxonomy' => 'product_shipping_class',
@@ -922,7 +984,7 @@
922
  'show_option_none' => __( 'No shipping class', 'woocommerce' ),
923
  'name' => 'multiple_variable_product_shipping_class',
924
  'id' => 'multiple_variable_product_shipping_class',
925
- 'selected' => $current_shipping_class,
926
  'class' => 'select short'
927
  );
928
 
@@ -1017,6 +1079,12 @@
1017
  <input type="text" class="small" name="variable_product_files_delim" value="<?php echo esc_attr($post['variable_product_files_delim']) ?>" style="width:5% !important;text-align:center; margin-left:5px;"/>
1018
  <a href="#help" class="help" title="<?php _e('File paths/URLs, comma separated. The delimiter option uses when xml element contains few paths/URLs (http://files.com/1.doc, http://files.com/2.doc).', 'pmxi_plugin') ?>">?</a>
1019
  </p>
 
 
 
 
 
 
1020
  <p class="form-field">
1021
  <label style="width:150px;"><?php _e('Download Limit','woocommerce');?></label>
1022
  <input type="text" value="<?php echo esc_attr($post['variable_download_limit']) ?>" style="" name="variable_download_limit" class="short">
@@ -1168,9 +1236,9 @@
1168
  <div class="variations_tree">
1169
  <div id="variations_xml">
1170
  <div class="variations_tag">
1171
- <input type="hidden" name="variations_tagno" value="<?php echo $tagno ?>" />
1172
  <div class="title">
1173
- <?php printf(__('No matching elements found for XPath expression specified', 'pmxi_plugin'), $tagno, $variation_list_count); ?>
1174
  </div>
1175
  <div class="clear"></div>
1176
  <div class="xml resetable"></div>
@@ -1190,15 +1258,23 @@
1190
  <div class="input">
1191
  <input type="radio" id="duplicate_indicator_title_parent" class="switcher" name="parent_indicator" value="title" <?php echo 'title' == $post['parent_indicator'] ? 'checked="checked"': '' ?>/>
1192
  <label for="duplicate_indicator_title_parent"><?php _e('title', 'pmxi_plugin' )?>&nbsp;</label>
 
 
1193
  <input type="radio" id="duplicate_indicator_content_parent" class="switcher" name="parent_indicator" value="content" <?php echo 'content' == $post['parent_indicator'] ? 'checked="checked"': '' ?>/>
1194
  <label for="duplicate_indicator_content_parent"><?php _e('content', 'pmxi_plugin' )?>&nbsp;</label>
 
 
1195
  <input type="radio" id="duplicate_indicator_custom_field_parent" class="switcher" name="parent_indicator" value="custom field" <?php echo 'custom field' == $post['parent_indicator'] ? 'checked="checked"': '' ?>/>
1196
  <label for="duplicate_indicator_custom_field_parent"><?php _e('custom field', 'pmxi_plugin' )?></label><br>
1197
  <span class="switcher-target-duplicate_indicator_custom_field_parent" style="vertical-align:middle" style="padding-left:17px;">
1198
- <?php _e('Name', 'pmxi_plugin') ?>
1199
- <input type="text" name="custom_parent_indicator_name" value="<?php echo esc_attr($post['custom_parent_indicator_name']) ?>" style="float:none; margin:1px;" /><br>
1200
- <?php _e('Value', 'pmxi_plugin') ?>
1201
- <input type="text" name="custom_parent_indicator_value" value="<?php echo esc_attr($post['custom_parent_indicator_value']) ?>" style="float:none; margin:1px; margin-left:3px;" />
 
 
 
 
1202
  </span>
1203
  </div>
1204
  </div>
@@ -1269,6 +1345,12 @@
1269
  <label for="disable_sku_matching"><?php _e('Disable SKU matching', 'pmxi_plugin') ?></label>
1270
  <a href="#help" class="help" title="<?php _e('Plugin will NOT search matches for SKU. This option will speed up import process.', 'pmxi_plugin') ?>" style="position:relative; top:-2px;">?</a>
1271
  </div>
 
 
 
 
 
 
1272
  </div>
1273
  </div>
1274
  </div>
30
  </div>
31
  </div>
32
  <div style="float:right;">
33
+ <label class="show_if_simple" for="_virtual" style="border-right:none;">
34
+ <input type="hidden" name="_virtual" value="0"/>
35
+ <?php _e('Virtual','woocommerce');?>: <input type="checkbox" id="_virtual" name="_virtual" <?php echo ($post['_virtual']) ? 'checked="checked"' : ''; ?>>
36
+ </label>
37
+ <label class="show_if_simple" for="_downloadable">
38
+ <input type="hidden" name="_downloadable" value="0"/>
39
+ <?php _e('Downloadable','woocommerce');?>: <input type="checkbox" id="_downloadable" name="_downloadable" <?php echo ($post['_downloadable']) ? 'checked="checked"' : ''; ?>>
40
+ </label>
41
  </div>
42
  </span>
43
  </h3>
171
  <input type="text" class="small" name="product_files_delim" value="<?php echo esc_attr($post['product_files_delim']) ?>" style="width:5%; text-align:center;"/>
172
  <a href="#help" class="help" title="<?php _e('File paths/URLs, comma separated. The delimiter is used when an XML element contains multiple URLs/paths - i.e. <code>http://files.com/1.doc, http://files.com/2.doc</code>.', 'pmxi_plugin') ?>">?</a>
173
  </p>
174
+ <p class="form-field">
175
+ <label><?php _e("File names"); ?></label>
176
+ <input type="text" class="short" name="single_product_files_names" value="<?php echo esc_attr($post['single_product_files_names']) ?>" style="margin-right:5px;"/>
177
+ <input type="text" class="small" name="product_files_names_delim" value="<?php echo esc_attr($post['product_files_names_delim']) ?>" style="width:5%; text-align:center;"/>
178
+ <a href="#help" class="help" title="<?php _e('File names, comma separated. The delimiter is used when an XML element contains multiple names - i.e. <code>1.doc, 2.doc</code>.', 'pmxi_plugin') ?>">?</a>
179
+ </p>
180
  <p class="form-field">
181
  <label><?php _e("Download Limit"); ?></label>
182
  <input type="text" class="short" placeholder="Unimited" name="single_product_download_limit" value="<?php echo esc_attr($post['single_product_download_limit']) ?>"/>&nbsp;
187
  <input type="text" class="short" placeholder="Never" name="single_product_download_expiry" value="<?php echo esc_attr($post['single_product_download_expiry']) ?>"/>&nbsp;
188
  <?php _e( 'Enter the number of days before a download link expires, or leave blank.', 'woocommerce' ) ?>
189
  </p>
190
+ <p class="form-field">
191
+ <label><?php _e("Download Type"); ?></label>
192
+ <input type="text" class="short" placeholder="Standard Product" name="single_product_download_type" value="<?php echo esc_attr($post['single_product_download_type']) ?>"/>&nbsp;
193
+ <a href="#help" class="help" title="<?php _e('The value of presented XPath should be one of the following: (\'application\', \'music\').', 'pmxi_plugin') ?>" style="position:relative; top:2px;">?</a>
194
+ </p>
195
  </div>
196
  <div class="options_group show_if_simple show_if_external show_if_variable">
197
  <div class="input">
472
  }
473
  }
474
  ?>
475
+
476
+ <div class="input">
477
+ <div class="main_choise">
478
+ <input type="radio" id="multiple_grouping_product_yes" class="switcher" name="is_multiple_grouping_product" value="yes" <?php echo 'no' != $post['is_multiple_grouping_product'] ? 'checked="checked"': '' ?>/>
479
+ <label for="multiple_grouping_product_yes"><?php _e("Grouping"); ?></label>
480
+ </div>
481
+ <div class="switcher-target-multiple_grouping_product_yes" style="padding-left:17px;">
482
+ <div class="input">
483
+ <select name="multiple_grouping_product">
484
+ <?php
485
+ foreach ($post_parents as $parent_id => $parent_title) {
486
+ ?>
487
+ <option value="<?php echo $parent_id; ?>" <?php if ($parent_id == $post['multiple_grouping_product']):?>selected="selected"<?php endif;?>><?php echo $parent_title;?></option>
488
+ <?php
489
+ }
490
+ ?>
491
+ </select>
492
+ <a href="#help" class="help" title="<?php _e('Set this option to make this product part of a grouped product.', 'woocommerce'); ?>">?</a>
493
+ </div>
494
+ </div>
495
+ </div>
496
+ <div class="input">
497
+ <div class="main_choise">
498
+ <input type="radio" id="multiple_grouping_product_no" class="switcher" name="is_multiple_grouping_product" value="no" <?php echo 'no' == $post['is_multiple_grouping_product'] ? 'checked="checked"': '' ?>/>
499
+ <label for="multiple_grouping_product_no"><?php _e('Manual matching grouping product with', 'pmxi_plugin' )?></label>
500
+ </div>
501
+
502
+ <div class="switcher-target-multiple_grouping_product_no" style="padding-left:17px; clear:both;">
503
+ <div class="input">
504
+ <input type="radio" id="duplicate_indicator_xpath_grouping" class="switcher" name="grouping_indicator" value="xpath" <?php echo 'xpath' == $post['grouping_indicator'] ? 'checked="checked"': '' ?>/>
505
+ <label for="duplicate_indicator_xpath_grouping"><?php _e('xpath', 'pmxi_plugin' )?></label>
506
+ <span class="switcher-target-duplicate_indicator_xpath_grouping" style="vertical-align:middle" style="padding-left:17px;">
507
+ <input type="text" name="single_grouping_product" value="<?php echo esc_attr($post['single_grouping_product']); ?>" style="float:none; margin:1px; margin-top:-3px;" />
508
+ <a href="#help" class="help" title="<?php _e('The value of presented XPath should be grouped product ID or Title).', 'pmxi_plugin') ?>">?</a>
509
+ </span>
510
+ </div>
511
+
512
+ <div class="input">
513
+ <input type="radio" id="duplicate_indicator_custom_field_grouping" class="switcher" name="grouping_indicator" value="custom field" <?php echo 'custom field' == $post['grouping_indicator'] ? 'checked="checked"': '' ?>/>
514
+ <label for="duplicate_indicator_custom_field_grouping"><?php _e('custom field', 'pmxi_plugin' )?></label><br>
515
+ <span class="switcher-target-duplicate_indicator_custom_field_grouping" style="vertical-align:middle" style="padding-left:17px;">
516
+ <div class="input">
517
+ <label><?php _e('Name', 'pmxi_plugin') ?></label>
518
+ <input type="text" name="custom_grouping_indicator_name" value="<?php echo esc_attr($post['custom_grouping_indicator_name']) ?>" style="float:none; margin:1px;" />
519
+ </div>
520
+ <div class="input">
521
+ <label><?php _e('Value', 'pmxi_plugin') ?></label>
522
+ <input type="text" name="custom_grouping_indicator_value" value="<?php echo esc_attr($post['custom_grouping_indicator_value']) ?>" style="float:none; margin:1px; margin-left:3px;" />
523
+ </div>
524
+ </span>
525
+
526
+
527
+ <!--input type="text" class="smaller-text" name="single_grouping_product" style="width:300px;" value="<?php echo esc_attr($post['single_grouping_product']) ?>"/>
528
+ <a href="#help" class="help" title="<?php _e('The value of presented XPath should be grouped product ID).', 'pmxi_plugin') ?>">?</a-->
529
+ </div>
530
+ </div>
531
+ </div>
532
+
533
  </div>
534
  </div><!-- End Product Panel -->
535
 
976
  <div class="input">
977
  <?php
978
  $classes = get_the_terms( 0, 'product_shipping_class' );
979
+ if ( $classes && ! is_wp_error( $classes ) ) $current_shipping_class = current($classes)->term_id; else $current_shipping_class = '';
980
 
981
  $args = array(
982
  'taxonomy' => 'product_shipping_class',
984
  'show_option_none' => __( 'No shipping class', 'woocommerce' ),
985
  'name' => 'multiple_variable_product_shipping_class',
986
  'id' => 'multiple_variable_product_shipping_class',
987
+ 'selected' => (!empty($post['multiple_variable_product_shipping_class'])) ? $post['multiple_variable_product_shipping_class'] : $current_shipping_class,
988
  'class' => 'select short'
989
  );
990
 
1079
  <input type="text" class="small" name="variable_product_files_delim" value="<?php echo esc_attr($post['variable_product_files_delim']) ?>" style="width:5% !important;text-align:center; margin-left:5px;"/>
1080
  <a href="#help" class="help" title="<?php _e('File paths/URLs, comma separated. The delimiter option uses when xml element contains few paths/URLs (http://files.com/1.doc, http://files.com/2.doc).', 'pmxi_plugin') ?>">?</a>
1081
  </p>
1082
+ <p class="form-field">
1083
+ <label style="width:150px;"><?php _e("File names"); ?></label>
1084
+ <input type="text" class="short" name="variable_file_names" value="<?php echo esc_attr($post['variable_file_names']) ?>" style="width:60% !important;"/>
1085
+ <input type="text" class="small" name="variable_product_files_names_delim" value="<?php echo esc_attr($post['variable_product_files_names_delim']) ?>" style="width:5% !important;text-align:center; margin-left:5px;"/>
1086
+ <a href="#help" class="help" title="<?php _e('File names, comma separated. The delimiter is used when an XML element contains multiple names - i.e. <code>1.doc, 2.doc</code>.', 'pmxi_plugin') ?>">?</a>
1087
+ </p>
1088
  <p class="form-field">
1089
  <label style="width:150px;"><?php _e('Download Limit','woocommerce');?></label>
1090
  <input type="text" value="<?php echo esc_attr($post['variable_download_limit']) ?>" style="" name="variable_download_limit" class="short">
1236
  <div class="variations_tree">
1237
  <div id="variations_xml">
1238
  <div class="variations_tag">
1239
+ <input type="hidden" name="variations_tagno" value="<?php echo (!empty($tagno)) ? $tagno : 0; ?>" />
1240
  <div class="title">
1241
+ <?php printf(__('No matching elements found for XPath expression specified', 'pmxi_plugin'), (!empty($tagno)) ? $tagno : 0, (!empty($variation_list_count)) ? $variation_list_count : 0); ?>
1242
  </div>
1243
  <div class="clear"></div>
1244
  <div class="xml resetable"></div>
1258
  <div class="input">
1259
  <input type="radio" id="duplicate_indicator_title_parent" class="switcher" name="parent_indicator" value="title" <?php echo 'title' == $post['parent_indicator'] ? 'checked="checked"': '' ?>/>
1260
  <label for="duplicate_indicator_title_parent"><?php _e('title', 'pmxi_plugin' )?>&nbsp;</label>
1261
+ </div>
1262
+ <div class="input">
1263
  <input type="radio" id="duplicate_indicator_content_parent" class="switcher" name="parent_indicator" value="content" <?php echo 'content' == $post['parent_indicator'] ? 'checked="checked"': '' ?>/>
1264
  <label for="duplicate_indicator_content_parent"><?php _e('content', 'pmxi_plugin' )?>&nbsp;</label>
1265
+ </div>
1266
+ <div class="input">
1267
  <input type="radio" id="duplicate_indicator_custom_field_parent" class="switcher" name="parent_indicator" value="custom field" <?php echo 'custom field' == $post['parent_indicator'] ? 'checked="checked"': '' ?>/>
1268
  <label for="duplicate_indicator_custom_field_parent"><?php _e('custom field', 'pmxi_plugin' )?></label><br>
1269
  <span class="switcher-target-duplicate_indicator_custom_field_parent" style="vertical-align:middle" style="padding-left:17px;">
1270
+ <div class="input">
1271
+ <label><?php _e('Name', 'pmxi_plugin') ?></label>
1272
+ <input type="text" name="custom_parent_indicator_name" value="<?php echo esc_attr($post['custom_parent_indicator_name']) ?>" style="float:none; margin:1px;" />
1273
+ </div>
1274
+ <div class="input">
1275
+ <label><?php _e('Value', 'pmxi_plugin') ?></label>
1276
+ <input type="text" name="custom_parent_indicator_value" value="<?php echo esc_attr($post['custom_parent_indicator_value']) ?>" style="float:none; margin:1px; margin-left:3px;" />
1277
+ </div>
1278
  </span>
1279
  </div>
1280
  </div>
1345
  <label for="disable_sku_matching"><?php _e('Disable SKU matching', 'pmxi_plugin') ?></label>
1346
  <a href="#help" class="help" title="<?php _e('Plugin will NOT search matches for SKU. This option will speed up import process.', 'pmxi_plugin') ?>" style="position:relative; top:-2px;">?</a>
1347
  </div>
1348
+ <div class="input" style="padding-left:20px;">
1349
+ <input type="hidden" name="disable_prepare_price" value="0" />
1350
+ <input type="checkbox" id="disable_prepare_price" name="disable_prepare_price" value="1" <?php echo $post['disable_prepare_price'] ? 'checked="checked"' : '' ?> />
1351
+ <label for="disable_prepare_price"><?php _e('Disable automatic fixing of improperly formatted prices.', 'pmxi_plugin') ?></label>
1352
+ <a href="#help" class="help" title="<?php _e('Plugin will NOT fix prices that presented with currency symbol.', 'pmxi_plugin') ?>" style="position:relative; top:-2px;">?</a>
1353
+ </div>
1354
  </div>
1355
  </div>
1356
  </div>