Import any XML or CSV File to WordPress - Version 2.14

Version Description

  • Category list delimiter bug fix
Download this release

Release Info

Developer soflyy
Plugin Icon 128x128 Import any XML or CSV File to WordPress
Version 2.14
Comparing to
See all releases

Code changes from version 2.13 to 2.14

actions/admin_menu.php CHANGED
@@ -5,18 +5,18 @@
5
 
6
  function pmxi_admin_menu() {
7
  global $menu, $submenu;
8
-
9
  if (current_user_can('manage_options')) { // admin management options
10
-
11
  add_menu_page(__('WP All Import', 'pmxi_plugin'), __('All Import', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-home', array(PMXI_Plugin::getInstance(), 'adminDispatcher'), PMXI_Plugin::ROOT_URL . '/static/img/xmlicon.png');
12
  // workaround to rename 1st option to `Home`
13
- $submenu['pmxi-admin-home'] = array();
14
  add_submenu_page('pmxi-admin-home', __('Import XML', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('New Import', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-import', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
15
  add_submenu_page('pmxi-admin-home', __('Manage Previous Imports', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('Manage Imports', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-manage', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
16
  add_submenu_page('pmxi-admin-home', __('Settings', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('Settings', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-settings', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
17
  //add_submenu_page('pmxi-admin-home', __('WP All Import', 'pmxi_plugin'), __('About', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-home', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
18
  // add_submenu_page('pmxi-admin-home', __('Help', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('Help', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-help', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
19
-
20
- }
21
  }
22
 
5
 
6
  function pmxi_admin_menu() {
7
  global $menu, $submenu;
8
+
9
  if (current_user_can('manage_options')) { // admin management options
10
+
11
  add_menu_page(__('WP All Import', 'pmxi_plugin'), __('All Import', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-home', array(PMXI_Plugin::getInstance(), 'adminDispatcher'), PMXI_Plugin::ROOT_URL . '/static/img/xmlicon.png');
12
  // workaround to rename 1st option to `Home`
13
+ $submenu['pmxi-admin-home'] = array();
14
  add_submenu_page('pmxi-admin-home', __('Import XML', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('New Import', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-import', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
15
  add_submenu_page('pmxi-admin-home', __('Manage Previous Imports', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('Manage Imports', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-manage', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
16
  add_submenu_page('pmxi-admin-home', __('Settings', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('Settings', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-settings', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
17
  //add_submenu_page('pmxi-admin-home', __('WP All Import', 'pmxi_plugin'), __('About', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-home', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
18
  // add_submenu_page('pmxi-admin-home', __('Help', 'pmxi_plugin') . ' ‹ ' . __('WP All Import', 'pmxi_plugin'), __('Help', 'pmxi_plugin'), 'manage_options', 'pmxi-admin-help', array(PMXI_Plugin::getInstance(), 'adminDispatcher'));
19
+
20
+ }
21
  }
22
 
config/options.php CHANGED
@@ -13,5 +13,6 @@ $config = array(
13
  "max_input_time" => -1,
14
  "max_execution_time" => -1,
15
  "dismiss" => 0,
16
- "html_entities" => 0
 
17
  );
13
  "max_input_time" => -1,
14
  "max_execution_time" => -1,
15
  "dismiss" => 0,
16
+ "html_entities" => 0,
17
+ "utf8_decode" => 0
18
  );
controllers/admin/import.php CHANGED
@@ -7,8 +7,7 @@
7
 
8
  class PMXI_Admin_Import extends PMXI_Controller_Admin {
9
  protected $isWizard = true; // indicates whether controller is in wizard mode (otherwize it called to be deligated an edit action)
10
- protected $isTemplateEdit = false; // indicates whether controlled is deligated by manage imports controller
11
- protected $csv_mimes = array('text/comma-separated-values','text/csv','application/csv','application/excel','application/vnd.ms-excel','application/vnd.msexcel','text/anytext');
12
 
13
  protected function init() {
14
  parent::init();
@@ -122,20 +121,89 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
122
  $this->errors->add('form-validation', __('XML/CSV file must be specified', 'pmxi_plugin'));
123
  } elseif (empty($_FILES['upload']['size'])) {
124
  $this->errors->add('form-validation', __('Uploaded file is empty', 'pmxi_plugin'));
125
- } elseif ( ! preg_match('%\W(xml|gzip|csv)$%i', trim($_FILES['upload']['name'])) and !$this->detect_csv($_FILES['upload']['type'])) {
126
- $this->errors->add('form-validation', __('Uploaded file must be XML, CSV or GZIP', 'pmxi_plugin'));
127
- } elseif ( preg_match('%\W(csv)$%i', trim($_FILES['upload']['name'])) or $this->detect_csv($_FILES['upload']['type'])) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  $uploads = wp_upload_dir();
129
  if($uploads['error']){
130
  $this->errors->add('form-validation', __('Can not create upload folder. Permision denied', 'pmxi_plugin'));
131
  }
132
  // copy file in temporary folder
133
- $fdata = file_get_contents($_FILES['upload']['tmp_name']);
134
- $fdata = utf8_encode($fdata);
135
  file_put_contents($uploads['path'] . '/' . trim(basename($_FILES['upload']['name'])), $fdata);
136
  chmod($uploads['path'] . '/'. trim(basename($_FILES['upload']['name'])), "0777");
137
  // end file convertion
138
- $xml = $this->csv_to_xml($uploads['path'] . '/' . trim(basename($_FILES['upload']['name'])));
139
  if( is_array($xml) && isset($xml['error'])){
140
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
141
  }
@@ -181,13 +249,89 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
181
  $this->errors->add('form-validation', __('XML/CSV file must be specified', 'pmxi_plugin'));
182
  } elseif ( ! preg_match('%^https?://%i', $post['url'])) {
183
  $this->errors->add('form-validation', __('Specified URL has wrong format'), 'pmxi_plugin');
184
- } elseif ( preg_match('%\W(csv)$%i', trim($post['url'])) or strpos(file_get_contents($post['url']), '<?xml') === false) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  $uploads = wp_upload_dir();
186
- $fdata = file_get_contents($post['url']);
187
- $fdata = utf8_encode($fdata);
188
  $tmpname = md5(time()).'.csv';
189
  file_put_contents($uploads['path'] .'/'. $tmpname, $fdata);
190
- $xml = $this->csv_to_xml($uploads['path'] .'/'. $tmpname);
191
  if( is_array($xml) && isset($xml['error'])){
192
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
193
  }
@@ -279,11 +423,10 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
279
  $url = $uploads['url'] . basename($local_file);
280
  // convert file to utf8
281
  chmod($uploads['path'] . basename($local_file), '0755');
282
- $fdata = file_get_contents($url);
283
- $fdata = utf8_encode($fdata);
284
  file_put_contents($uploads['path'] . basename($local_file), $fdata);
285
  // end file convertion
286
- $xml = $this->csv_to_xml($uploads['path'] . basename($local_file));
287
  if( is_array($xml) && isset($xml['error'])){
288
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
289
  }
@@ -344,11 +487,10 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
344
  $url = $wp_uploads['url'] . basename($post['file']);
345
  // convert file to utf8
346
  chmod($wp_uploads['path'] . basename($post['file']), '0755');
347
- $fdata = file_get_contents($url);
348
- $fdata = utf8_encode($fdata);
349
  file_put_contents($wp_uploads['path'] . basename($post['file']), $fdata);
350
  // end file convertion
351
- $xml = $this->csv_to_xml($wp_uploads['path'] . basename($post['file']));
352
  if( is_array($xml) && isset($xml['error'])){
353
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
354
  }
@@ -408,12 +550,16 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
408
  if ( ! $reimport_id or $file->getById($reimport_id)->isEmpty()) {
409
  $xml = FALSE;
410
  } else {
411
- $xml = $file->contents;
 
 
 
412
  $source = array(
413
  'name' => $file->name,
414
  'type' => 'reimport',
415
  'path' => $file->path,
416
  );
 
417
  }
418
  } else {
419
  if (in_array($this->input->post('type'), array('ftp', 'file'))) { // file may be specified by pattern
@@ -424,12 +570,19 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
424
  $filePath = FALSE;
425
  }
426
  }
427
-
428
  ob_start();
429
  $filePath && @readgzfile($filePath);
430
 
431
  $xml = ob_get_clean();
432
 
 
 
 
 
 
 
 
433
  }
434
 
435
  if (PMXI_Import_Record::validateXml($xml, $this->errors)) {
@@ -808,7 +961,7 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
808
  $this->errors->add('form-validation', __('Order must be an integer number', 'pmxi_plugin'));
809
  }
810
  if ('post' == $post['type']) {
811
- '' == $post['categories'] or $this->_validate_template($post['categories'], __('Categories', 'pmxi_plugin'));
812
  '' == $post['tags'] or $this->_validate_template($post['tags'], __('Tags', 'pmxi_plugin'));
813
  }
814
  if ('specific' == $post['date_type']) {
@@ -816,10 +969,7 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
816
  } else {
817
  '' == $post['date_start'] or $this->_validate_template($post['date_start'], __('Start Date', 'pmxi_plugin'));
818
  '' == $post['date_end'] or $this->_validate_template($post['date_end'], __('Start Date', 'pmxi_plugin'));
819
- }
820
- if ('' == $post['categories_delim']) {
821
- $this->errors->add('form-validation', __('Category list delimiter cannot be empty', 'pmxi_plugin'));
822
- }
823
  if ('' == $post['tags_delim']) {
824
  $this->errors->add('form-validation', __('Tag list delimiter must cannot be empty', 'pmxi_plugin'));
825
  }
@@ -832,7 +982,10 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
832
  if ( ! preg_match('%^([1-9]\d*)( *- *([1-9]\d*))?$%', $chank, $mtch)) {
833
  $this->errors->add('form-validation', __('Wrong format of `Import only specified records` value', 'pmxi_plugin'));
834
  break;
835
- }
 
 
 
836
  }
837
  }
838
  }
@@ -868,7 +1021,7 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
868
  }
869
 
870
  if ( ! $this->input->post('save_only')) {
871
- $this->process();die();
872
  } else {
873
  $import = $this->data['update_previous'];
874
  $is_update = ! $import->isEmpty();
@@ -895,6 +1048,13 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
895
  }
896
  } else {
897
  $this->data['import']->set('options', $post)->set('scheduled', $scheduled['is_scheduled'] ? $scheduled['scheduled_period'] : '')->save();
 
 
 
 
 
 
 
898
  wp_redirect(add_query_arg(array('page' => 'pmxi-admin-manage', 'pmlc_nt' => urlencode(__('Options updated', 'pmxi_plugin'))) + array_intersect_key($_GET, array_flip($this->baseUrlParamNames)), admin_url('admin.php'))); die();
899
  }
900
  }
@@ -904,65 +1064,40 @@ class PMXI_Admin_Import extends PMXI_Controller_Admin {
904
 
905
  $this->render();
906
  }
907
-
908
  /**
909
  * Import processing step (status console)
910
  */
911
  public function process()
912
- {
913
- wp_ob_end_flush_all(); flush();
 
 
 
914
 
915
  // store import info in database
916
  $import = $this->data['update_previous'];
 
 
 
 
 
 
 
 
 
917
 
918
- if ($_SESSION['pmxi_import']['options']['is_first_chank'] or !$_SESSION['pmxi_import']['options']['is_update_previous'])
919
- {
920
- $_SESSION['pmxi_import']['step'] = 0;
921
- $import->set(
922
- $_SESSION['pmxi_import']['source']
923
- + array(
924
- 'xpath' => $_SESSION['pmxi_import']['xpath'],
925
- 'template' => $_SESSION['pmxi_import']['template'],
926
- 'options' => $_SESSION['pmxi_import']['options'],
927
- 'scheduled' => $_SESSION['pmxi_import']['scheduled']
928
- )
929
- )->save();
930
-
931
- $history_file = new PMXI_File_Record();
932
- $history_file->set(array(
933
- 'name' => $import->name,
934
- 'import_id' => $import->id,
935
- 'path' => $import->path,
936
- 'contents' => $_SESSION['pmxi_import']['xml'],
937
- 'registered_on' => date('Y-m-d H:i:s'),
938
- ))->save();
939
-
940
- $_SESSION['pmxi_import']['import_start'] = date('H:i:s');
941
- }
942
- else
943
- {
944
- $_SESSION['pmxi_import']['step']++;
945
- $import = new PMXI_Import_Record();
946
- $import->getById($_SESSION['pmxi_import']['options']['is_update_previous']);
947
- }
948
-
949
  $logger = create_function('$m', 'echo "<div class=\\"progress-msg\\">$m</div>\\n"; flush();');
 
950
  if (in_array($import->type, array('ftp', 'file'))) { // process files by patten
951
  $import->execute($logger);
952
  } else { // directly process XML
953
- set_time_limit(0);
954
- $xml = new SimpleXMLElement($_SESSION['pmxi_import']['xml']);
955
- $rootNodes = $xml->xpath($_SESSION['pmxi_import']['xpath']);
956
- $this->removeNode($xml, $_SESSION['pmxi_import']['xpath'].'[position() >= 10]');
957
-
958
- if (count($xml->xpath($_SESSION['pmxi_import']['xpath'])))
959
- {
960
- ob_start();
961
- $import->process($xml->asXML(), $logger, ((count($rootNodes) < 10) ? true : false));
962
 
963
- if ((count($rootNodes) < 10))
964
- {
965
- // [indicate in header process is complete]
966
  $msg = addcslashes(__('Complete', 'pmxi_plugin'), "'\n\r");
967
  echo <<<COMPLETE
968
  <script type="text/javascript">
@@ -975,29 +1110,8 @@ echo <<<COMPLETE
975
  </script>
976
  COMPLETE;
977
  // [/indicate in header process is complete]
978
- }
979
- $log = ob_get_clean();
980
- }
981
- unset($xml);
982
-
983
- $xml_chank = new SimpleXMLElement($_SESSION['pmxi_import']['xml']);
984
- $this->removeNode($xml_chank, $_SESSION['pmxi_import']['xpath'].'[position() < 10]');
985
-
986
- $_SESSION['pmxi_import']['xml'] = (count($rootNodes) >= 10) ? $xml_chank->asXML() : NULL;
987
- unset($xml_chank);
988
- }
989
-
990
- if (!empty($_SESSION['pmxi_import']['xml']))
991
- exit(json_encode(array('status' => 'process','update_previous' => $import->__get('id'), 'count' => count($rootNodes), 'is_last_chank' => ((count($rootNodes) < 10) ? true : false), 'is_first_chank' => $_SESSION['pmxi_import']['options']['is_first_chank'], 'log' => $log)));
992
- else {
993
- $start_time = $_SESSION['pmxi_import']['import_start'];
994
- $end_time = date('H:i:s');
995
- unset($_SESSION['pmxi_import']); // clear session data (prevent from reimporting the same data on page refresh)
996
- exit(json_encode(array('status' => 'stop', 'log' => $log, 'start_time' => $start_time, 'end_time' => $end_time, 'import_time' => date('H:i:s', strtotime($end_time) - strtotime($start_time)))));
997
- };
998
-
999
-
1000
  }
 
1001
  /**
1002
  * Remove xml document nodes by xpath expression
1003
  */
@@ -1281,25 +1395,6 @@ COMPLETE;
1281
  }
1282
 
1283
  return NULL;
1284
- }
1285
- /*
1286
- * Convert csv to xml using yahoo API
1287
- */
1288
- protected function csv_to_xml($csv_url){
1289
-
1290
- include_once(PMXI_Plugin::ROOT_DIR.'/libraries/XmlImportCsvParse.php');
1291
-
1292
- $csv = new PMXI_CsvParser($csv_url);
1293
-
1294
- return $csv->toXML();
1295
-
1296
- }
1297
- /*
1298
- *
1299
- * Detect CSV file
1300
- *
1301
- */
1302
- protected function detect_csv($type){
1303
- return in_array($type, $this->csv_mimes);
1304
- }
1305
  }
7
 
8
  class PMXI_Admin_Import extends PMXI_Controller_Admin {
9
  protected $isWizard = true; // indicates whether controller is in wizard mode (otherwize it called to be deligated an edit action)
10
+ protected $isTemplateEdit = false; // indicates whether controlled is deligated by manage imports controller
 
11
 
12
  protected function init() {
13
  parent::init();
121
  $this->errors->add('form-validation', __('XML/CSV file must be specified', 'pmxi_plugin'));
122
  } elseif (empty($_FILES['upload']['size'])) {
123
  $this->errors->add('form-validation', __('Uploaded file is empty', 'pmxi_plugin'));
124
+ } elseif ( ! preg_match('%\W(xml|gzip|zip|csv|gz)$%i', trim($_FILES['upload']['name'])) and !PMXI_Plugin::detect_csv($_FILES['upload']['type'])) {
125
+ $this->errors->add('form-validation', __('Uploaded file must be XML, CSV or ZIP, GZIP', 'pmxi_plugin'));
126
+ } elseif (preg_match('%\W(zip)$%i', trim($_FILES['upload']['name']))) {
127
+
128
+ $zip = zip_open(trim($_FILES['upload']['tmp_name']));
129
+ if (is_resource($zip)) {
130
+ $uploads = wp_upload_dir();
131
+ if($uploads['error']){
132
+ $this->errors->add('form-validation', __('Can not create upload folder. Permision denied', 'pmxi_plugin'));
133
+ }
134
+ $filename = '';
135
+ while ($zip_entry = zip_read($zip)) {
136
+ $filename = zip_entry_name($zip_entry);
137
+ $fp = fopen($uploads['path']."/".$filename, "w");
138
+ if (zip_entry_open($zip, $zip_entry, "r")) {
139
+ $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
140
+ fwrite($fp,"$buf");
141
+ zip_entry_close($zip_entry);
142
+ fclose($fp);
143
+ }
144
+ break;
145
+ }
146
+ zip_close($zip);
147
+
148
+ if (preg_match('%\W(csv)$%i', trim($filename))){
149
+
150
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] . '/' . trim($filename));
151
+ if( is_array($xml) && isset($xml['error'])){
152
+ $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
153
+ }
154
+ else {
155
+
156
+ // delete file in temporary folder
157
+ unlink( $uploads['path'] .'/'. trim($filename));
158
+ $fullfilename = $uploads['path']."/".$filename;
159
+ // Let's make sure the file exists and is writable first.
160
+
161
+ if (!$handle = fopen($fullfilename, 'w')) {
162
+ $this->errors->add('form-validation', __('Cannot open file ' . $fullfilename, 'pmxi_plugin'));
163
+ }
164
+
165
+ // Write $somecontent to our opened file.
166
+ if (fwrite($handle, $xml) === FALSE) {
167
+ $this->errors->add('form-validation', __('Cannot write to file ' . $fullfilename, 'pmxi_plugin'));
168
+ }
169
+
170
+ fclose($handle);
171
+
172
+
173
+ $filePath = $fullfilename;
174
+ $source = array(
175
+ 'name' => $filename,
176
+ 'type' => 'upload',
177
+ 'path' => '',
178
+ );
179
+ }
180
+
181
+ }
182
+ else
183
+ {
184
+ $filePath = $uploads['path']."/".$filename;
185
+ $source = array(
186
+ 'name' => $filename,
187
+ 'type' => 'upload',
188
+ 'path' => '',
189
+ );
190
+ }
191
+
192
+ } else {
193
+ $this->errors->add('form-validation', __('Failed to open uploaded ZIP archive', 'pmxi_plugin'));
194
+ }
195
+
196
+ } elseif ( preg_match('%\W(csv)$%i', trim($_FILES['upload']['name'])) or PMXI_Plugin::detect_csv($_FILES['upload']['type'])) {
197
  $uploads = wp_upload_dir();
198
  if($uploads['error']){
199
  $this->errors->add('form-validation', __('Can not create upload folder. Permision denied', 'pmxi_plugin'));
200
  }
201
  // copy file in temporary folder
202
+ $fdata = file_get_contents($_FILES['upload']['tmp_name']);
 
203
  file_put_contents($uploads['path'] . '/' . trim(basename($_FILES['upload']['name'])), $fdata);
204
  chmod($uploads['path'] . '/'. trim(basename($_FILES['upload']['name'])), "0777");
205
  // end file convertion
206
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] . '/' . trim(basename($_FILES['upload']['name'])));
207
  if( is_array($xml) && isset($xml['error'])){
208
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
209
  }
249
  $this->errors->add('form-validation', __('XML/CSV file must be specified', 'pmxi_plugin'));
250
  } elseif ( ! preg_match('%^https?://%i', $post['url'])) {
251
  $this->errors->add('form-validation', __('Specified URL has wrong format'), 'pmxi_plugin');
252
+ } elseif (preg_match('%\W(zip)$%i', trim($post['url']))) {
253
+
254
+ $uploads = wp_upload_dir();
255
+
256
+ $newfile = $uploads['path']."/".md5(time()).'.zip';
257
+
258
+ if (!copy($post['url'], $newfile)) {
259
+ $this->errors->add('form-validation', __('Failed upload ZIP archive', 'pmxi_plugin'));
260
+ }
261
+
262
+ $zip = zip_open($newfile);
263
+ if (is_resource($zip)) {
264
+ $uploads = wp_upload_dir();
265
+ if($uploads['error']){
266
+ $this->errors->add('form-validation', __('Can not create upload folder. Permision denied', 'pmxi_plugin'));
267
+ }
268
+ $filename = '';
269
+ while ($zip_entry = zip_read($zip)) {
270
+ $filename = zip_entry_name($zip_entry);
271
+ $fp = fopen($uploads['path']."/".$filename, "w");
272
+ if (zip_entry_open($zip, $zip_entry, "r")) {
273
+ $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
274
+ fwrite($fp,"$buf");
275
+ zip_entry_close($zip_entry);
276
+ fclose($fp);
277
+ }
278
+ break;
279
+ }
280
+ zip_close($zip);
281
+ unlink($newfile);
282
+ if (preg_match('%\W(csv)$%i', trim($filename))){
283
+
284
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] . '/' . trim($filename));
285
+ if( is_array($xml) && isset($xml['error'])){
286
+ $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
287
+ }
288
+ else {
289
+
290
+ // delete file in temporary folder
291
+ unlink( $uploads['path'] .'/'. trim($filename));
292
+ $fullfilename = $uploads['path']."/".$filename;
293
+ // Let's make sure the file exists and is writable first.
294
+
295
+ if (!$handle = fopen($fullfilename, 'w')) {
296
+ $this->errors->add('form-validation', __('Cannot open file ' . $fullfilename, 'pmxi_plugin'));
297
+ }
298
+
299
+ // Write $somecontent to our opened file.
300
+ if (fwrite($handle, $xml) === FALSE) {
301
+ $this->errors->add('form-validation', __('Cannot write to file ' . $fullfilename, 'pmxi_plugin'));
302
+ }
303
+
304
+ fclose($handle);
305
+
306
+
307
+ $filePath = $fullfilename;
308
+ $source = array(
309
+ 'name' => $filename,
310
+ 'type' => 'url',
311
+ 'path' => $post['url'],
312
+ );
313
+ }
314
+
315
+ }
316
+ else
317
+ {
318
+ $filePath = $uploads['path']."/".$filename;
319
+ $source = array(
320
+ 'name' => $filename,
321
+ 'type' => 'url',
322
+ 'path' => $post['url'],
323
+ );
324
+ }
325
+
326
+ } else {
327
+ $this->errors->add('form-validation', __('Failed to open uploaded ZIP archive', 'pmxi_plugin'));
328
+ }
329
+ } elseif ( preg_match('%\W(csv)$%i', trim($post['url'])) or $contents = get_headers($post['url'],1 ) and PMXI_Plugin::detect_csv($contents['Content-Type'])) {
330
  $uploads = wp_upload_dir();
331
+ $fdata = file_get_contents($post['url']);
 
332
  $tmpname = md5(time()).'.csv';
333
  file_put_contents($uploads['path'] .'/'. $tmpname, $fdata);
334
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] .'/'. $tmpname);
335
  if( is_array($xml) && isset($xml['error'])){
336
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
337
  }
423
  $url = $uploads['url'] . basename($local_file);
424
  // convert file to utf8
425
  chmod($uploads['path'] . basename($local_file), '0755');
426
+ $fdata = file_get_contents($url);
 
427
  file_put_contents($uploads['path'] . basename($local_file), $fdata);
428
  // end file convertion
429
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] . basename($local_file));
430
  if( is_array($xml) && isset($xml['error'])){
431
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
432
  }
487
  $url = $wp_uploads['url'] . basename($post['file']);
488
  // convert file to utf8
489
  chmod($wp_uploads['path'] . basename($post['file']), '0755');
490
+ $fdata = file_get_contents($url);
 
491
  file_put_contents($wp_uploads['path'] . basename($post['file']), $fdata);
492
  // end file convertion
493
+ $xml = PMXI_Plugin::csv_to_xml($wp_uploads['path'] . basename($post['file']));
494
  if( is_array($xml) && isset($xml['error'])){
495
  $this->errors->add('form-validation', __($xml['error'], 'pmxi_plugin'));
496
  }
550
  if ( ! $reimport_id or $file->getById($reimport_id)->isEmpty()) {
551
  $xml = FALSE;
552
  } else {
553
+ $xml = @file_get_contents($file->path);
554
+
555
+ if ($contents = get_headers($file->path,1 ) and PMXI_Plugin::detect_csv($contents['Content-Type'])) $xml = PMXI_Plugin::csv_to_xml($file->path);
556
+
557
  $source = array(
558
  'name' => $file->name,
559
  'type' => 'reimport',
560
  'path' => $file->path,
561
  );
562
+
563
  }
564
  } else {
565
  if (in_array($this->input->post('type'), array('ftp', 'file'))) { // file may be specified by pattern
570
  $filePath = FALSE;
571
  }
572
  }
573
+
574
  ob_start();
575
  $filePath && @readgzfile($filePath);
576
 
577
  $xml = ob_get_clean();
578
 
579
+ $wp_uploads = wp_upload_dir();
580
+ $url = $wp_uploads['url'] .'/'. basename($filePath);
581
+ file_put_contents($wp_uploads['path'] .'/'. basename($filePath), $xml);
582
+ chmod($wp_uploads['path'] .'/'. basename($filePath), '0755');
583
+
584
+ if ($contents = get_headers($url,1 ) and PMXI_Plugin::detect_csv($contents['Content-Type'])) $xml = PMXI_Plugin::csv_to_xml($wp_uploads['path']. basename($filePath));
585
+
586
  }
587
 
588
  if (PMXI_Import_Record::validateXml($xml, $this->errors)) {
961
  $this->errors->add('form-validation', __('Order must be an integer number', 'pmxi_plugin'));
962
  }
963
  if ('post' == $post['type']) {
964
+ /*'' == $post['categories'] or $this->_validate_template($post['categories'], __('Categories', 'pmxi_plugin'));*/
965
  '' == $post['tags'] or $this->_validate_template($post['tags'], __('Tags', 'pmxi_plugin'));
966
  }
967
  if ('specific' == $post['date_type']) {
969
  } else {
970
  '' == $post['date_start'] or $this->_validate_template($post['date_start'], __('Start Date', 'pmxi_plugin'));
971
  '' == $post['date_end'] or $this->_validate_template($post['date_end'], __('Start Date', 'pmxi_plugin'));
972
+ }
 
 
 
973
  if ('' == $post['tags_delim']) {
974
  $this->errors->add('form-validation', __('Tag list delimiter must cannot be empty', 'pmxi_plugin'));
975
  }
982
  if ( ! preg_match('%^([1-9]\d*)( *- *([1-9]\d*))?$%', $chank, $mtch)) {
983
  $this->errors->add('form-validation', __('Wrong format of `Import only specified records` value', 'pmxi_plugin'));
984
  break;
985
+ } elseif ($this->isWizard and (intval($mtch[1]) > $this->data['elements']->length or isset($mtch[3]) and intval($mtch[3]) > $this->data['elements']->length)) {
986
+ $this->errors->add('form-validation', __('One of the numbers in `Import only specified records` value exceeds record quantity in XML file', 'pmxi_plugin'));
987
+ break;
988
+ }
989
  }
990
  }
991
  }
1021
  }
1022
 
1023
  if ( ! $this->input->post('save_only')) {
1024
+ wp_redirect(add_query_arg('action', 'process', $this->baseUrl)); die();
1025
  } else {
1026
  $import = $this->data['update_previous'];
1027
  $is_update = ! $import->isEmpty();
1048
  }
1049
  } else {
1050
  $this->data['import']->set('options', $post)->set('scheduled', $scheduled['is_scheduled'] ? $scheduled['scheduled_period'] : '')->save();
1051
+ $template = new PMXI_Template_Record();
1052
+
1053
+ if (!$template->getByName($this->data['import']->template['name'])->isEmpty()){
1054
+ $template->set(array(
1055
+ 'options' => $post,
1056
+ 'scheduled' => ($scheduled['is_scheduled'] ? $scheduled['scheduled_period'] : '')))->update();
1057
+ }
1058
  wp_redirect(add_query_arg(array('page' => 'pmxi-admin-manage', 'pmlc_nt' => urlencode(__('Options updated', 'pmxi_plugin'))) + array_intersect_key($_GET, array_flip($this->baseUrlParamNames)), admin_url('admin.php'))); die();
1059
  }
1060
  }
1064
 
1065
  $this->render();
1066
  }
1067
+
1068
  /**
1069
  * Import processing step (status console)
1070
  */
1071
  public function process()
1072
+ {
1073
+ $this->render();
1074
+ wp_ob_end_flush_all(); flush();
1075
+
1076
+ set_time_limit(0);
1077
 
1078
  // store import info in database
1079
  $import = $this->data['update_previous'];
1080
+ $import->set(
1081
+ $_SESSION['pmxi_import']['source']
1082
+ + array(
1083
+ 'xpath' => $_SESSION['pmxi_import']['xpath'],
1084
+ 'template' => $_SESSION['pmxi_import']['template'],
1085
+ 'options' => $_SESSION['pmxi_import']['options'],
1086
+ 'scheduled' => $_SESSION['pmxi_import']['scheduled']
1087
+ )
1088
+ )->save();
1089
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1090
  $logger = create_function('$m', 'echo "<div class=\\"progress-msg\\">$m</div>\\n"; flush();');
1091
+
1092
  if (in_array($import->type, array('ftp', 'file'))) { // process files by patten
1093
  $import->execute($logger);
1094
  } else { // directly process XML
1095
+ $import->process($_SESSION['pmxi_import']['xml'], $logger);
1096
+ }
1097
+
1098
+ unset($_SESSION['pmxi_import']); // clear session data (prevent from reimporting the same data on page refresh)
 
 
 
 
 
1099
 
1100
+ // [indicate in header process is complete]
 
 
1101
  $msg = addcslashes(__('Complete', 'pmxi_plugin'), "'\n\r");
1102
  echo <<<COMPLETE
1103
  <script type="text/javascript">
1110
  </script>
1111
  COMPLETE;
1112
  // [/indicate in header process is complete]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1113
  }
1114
+
1115
  /**
1116
  * Remove xml document nodes by xpath expression
1117
  */
1395
  }
1396
 
1397
  return NULL;
1398
+ }
1399
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1400
  }
controllers/admin/manage.php CHANGED
@@ -22,8 +22,8 @@ class PMXI_Admin_Manage extends PMXI_Controller_Admin {
22
 
23
  $get = $this->input->get(array(
24
  's' => '',
25
- 'order_by' => 'name',
26
- 'order' => 'ASC',
27
  'pagenum' => 1,
28
  'perPage' => 10,
29
  ));
@@ -58,6 +58,96 @@ class PMXI_Admin_Manage extends PMXI_Controller_Admin {
58
  $this->render();
59
  }
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  /**
62
  * Delete an import
63
  */
22
 
23
  $get = $this->input->get(array(
24
  's' => '',
25
+ 'order_by' => 'ID',
26
+ 'order' => 'DESC',
27
  'pagenum' => 1,
28
  'perPage' => 10,
29
  ));
58
  $this->render();
59
  }
60
 
61
+ /**
62
+ * Reimport
63
+ */
64
+ public function update() {
65
+ $id = $this->input->get('id');
66
+ $this->data['item'] = $item = new PMXI_Import_Record();
67
+ if ( ! $id or $item->getById($id)->isEmpty()) {
68
+ wp_redirect($this->baseUrl); die();
69
+ }
70
+
71
+ if ($this->input->post('is_confirmed')) {
72
+ check_admin_referer('update-import', '_wpnonce_update-import');
73
+
74
+ if (in_array($item->type, array('ftp', 'file'))) {
75
+ $xml = '';
76
+ } else {
77
+
78
+ $contents = get_headers($item->path,1 );
79
+
80
+ if (preg_match('%\W(zip)$%i', trim($item->path))){
81
+
82
+ $uploads = wp_upload_dir();
83
+
84
+ $newfile = $uploads['path']."/".md5(time()).'.zip';
85
+
86
+ if (!copy($item->path, $newfile)) {
87
+ $this->errors->add('form-validation', __('Failed upload ZIP archive', 'pmxi_plugin'));
88
+ }
89
+
90
+ $zip = zip_open($newfile);
91
+ if (is_resource($zip)) {
92
+ $uploads = wp_upload_dir();
93
+ if($uploads['error']){
94
+ $this->errors->add('form-validation', __('Can not create upload folder. Permision denied', 'pmxi_plugin'));
95
+ }
96
+ $filename = '';
97
+ while ($zip_entry = zip_read($zip)) {
98
+ $filename = zip_entry_name($zip_entry);
99
+ $fp = fopen($uploads['path']."/".$filename, "w");
100
+ if (zip_entry_open($zip, $zip_entry, "r")) {
101
+ $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
102
+ fwrite($fp,"$buf");
103
+ zip_entry_close($zip_entry);
104
+ fclose($fp);
105
+ }
106
+ break;
107
+ }
108
+ zip_close($zip);
109
+ unlink($newfile);
110
+ if (preg_match('%\W(csv)$%i', trim($filename)) or PMXI_Plugin::detect_csv($contents['Content-Type']))
111
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] .'/'. $filename);
112
+ else
113
+ $xml = @file_get_contents($uploads['path'] .'/'. $filename);
114
+ }
115
+
116
+ } elseif (preg_match('%\W(csv)$%i', trim($item->path)) or PMXI_Plugin::detect_csv($contents['Content-Type'])) {
117
+ $uploads = wp_upload_dir();
118
+ $fdata = file_get_contents($item->path);
119
+ $tmpname = md5(time()).'.csv';
120
+ file_put_contents($uploads['path'] .'/'. $tmpname, $fdata);
121
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] .'/'. $tmpname);
122
+ }
123
+ else
124
+ $xml = @file_get_contents($item->path);
125
+ }
126
+ if (in_array($item->type, array('ftp', 'file')) or PMXI_Import_Record::validateXml($xml, $this->errors)) { // xml is valid
127
+ // compose data to look like result of wizard steps
128
+ $_SESSION['pmxi_import'] = array(
129
+ 'xml' => $xml,
130
+ 'source' => array(
131
+ 'name' => $item->name,
132
+ 'type' => $item->type,
133
+ 'path' => $item->path,
134
+ ),
135
+ 'update_previous' => $item->id,
136
+ 'xpath' => $item->xpath,
137
+ 'template' => $item->template,
138
+ 'options' => $item->options,
139
+ );
140
+ // deligate operation to other controller
141
+ $controller = new PMXI_Admin_Import();
142
+ $controller->data['update_previous'] = $item;
143
+ $controller->process();
144
+ return;
145
+ }
146
+
147
+ }
148
+ $this->render();
149
+ }
150
+
151
  /**
152
  * Delete an import
153
  */
controllers/admin/settings.php CHANGED
@@ -19,6 +19,7 @@ class PMXI_Admin_Settings extends PMXI_Controller_Admin {
19
  $this->errors->add('form-validation', __('History Age must be a non-negative integer', 'pmxi_plugin'));
20
  }
21
  if (empty($post['html_entities'])) $post['html_entities'] = 0;
 
22
 
23
  if ( ! $this->errors->get_error_codes()) { // no validation errors detected
24
 
@@ -52,5 +53,5 @@ class PMXI_Admin_Settings extends PMXI_Controller_Admin {
52
 
53
  exit('OK');
54
  }
55
-
56
  }
19
  $this->errors->add('form-validation', __('History Age must be a non-negative integer', 'pmxi_plugin'));
20
  }
21
  if (empty($post['html_entities'])) $post['html_entities'] = 0;
22
+ if (empty($post['utf8_decode'])) $post['utf8_decode'] = 0;
23
 
24
  if ( ! $this->errors->get_error_codes()) { // no validation errors detected
25
 
53
 
54
  exit('OK');
55
  }
56
+
57
  }
controllers/controller/admin.php CHANGED
@@ -54,6 +54,7 @@ abstract class PMXI_Controller_Admin extends PMXI_Controller {
54
  wp_enqueue_script('jquery-ui-datepicker', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/jquery/ui.datepicker.js', 'jquery-ui-core');
55
  wp_enqueue_script('jquery-ui-autocomplete', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/jquery/ui.autocomplete.js', array('jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-position'));
56
  wp_enqueue_script('jquery-tipsy', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/jquery/jquery.tipsy.js', 'jquery');
 
57
 
58
  wp_enqueue_script('pmxi-admin-script', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/admin.js', array('jquery', 'jquery-ui-dialog', 'jquery-ui-datepicker', 'jquery-ui-draggable', 'jquery-ui-droppable'));
59
 
54
  wp_enqueue_script('jquery-ui-datepicker', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/jquery/ui.datepicker.js', 'jquery-ui-core');
55
  wp_enqueue_script('jquery-ui-autocomplete', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/jquery/ui.autocomplete.js', array('jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-position'));
56
  wp_enqueue_script('jquery-tipsy', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/jquery/jquery.tipsy.js', 'jquery');
57
+ wp_enqueue_script('jquery-nestable', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/jquery/jquery.mjs.nestedSortable.js', array('jquery', 'jquery-ui-dialog', 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable'));
58
 
59
  wp_enqueue_script('pmxi-admin-script', PMXI_Plugin::getInstance()->getRelativePath() . '/static/js/admin.js', array('jquery', 'jquery-ui-dialog', 'jquery-ui-datepicker', 'jquery-ui-draggable', 'jquery-ui-droppable'));
60
 
libraries/XmlImportConfig.php CHANGED
@@ -43,10 +43,10 @@ if (!class_exists('XmlImportConfig'))
43
  */
44
  public static function getInstance()
45
  {
46
- if (is_null(self::$instance)) {
47
  self::$instance = new self;
48
  self::$instance->init();
49
- }
50
  return self::$instance;
51
  }
52
 
43
  */
44
  public static function getInstance()
45
  {
46
+ //if (is_null(self::$instance)) {
47
  self::$instance = new self;
48
  self::$instance->init();
49
+ //}
50
  return self::$instance;
51
  }
52
 
libraries/XmlImportCsvParse.php CHANGED
@@ -110,6 +110,8 @@ class PMXI_CsvParser
110
  */
111
  public function __construct($filename = null)
112
  {
 
 
113
  ini_set('auto_detect_line_endings', true);
114
 
115
  $file_params = self::analyse_file($filename, 10);
@@ -2165,7 +2167,7 @@ class PMXI_CsvParser
2165
 
2166
  if ($c == 0) {
2167
  foreach ($keys as $key => $value) {
2168
- if (preg_match('%\W(http:|https:|ftp:)$%i', $value) or strlen($value) > 15 or is_numeric($value)) {
2169
  $create_new_headers = true;
2170
  break;
2171
  }
@@ -2285,7 +2287,7 @@ class PMXI_CsvParser
2285
  }
2286
 
2287
  public function toXml() {
2288
- $this->symmetrize();
2289
  return ArrayToXML::toXml($this->getRawArray());
2290
  }
2291
 
@@ -2411,7 +2413,7 @@ class ArrayToXML
2411
  else
2412
  {
2413
  // add single node.
2414
- //$value = htmlentities($value);
2415
  $xml->addChild($key,$value);
2416
  }
2417
 
110
  */
111
  public function __construct($filename = null)
112
  {
113
+
114
+ ini_set( "display_errors", 0);
115
  ini_set('auto_detect_line_endings', true);
116
 
117
  $file_params = self::analyse_file($filename, 10);
2167
 
2168
  if ($c == 0) {
2169
  foreach ($keys as $key => $value) {
2170
+ if (preg_match('%\W(http:|https:|ftp:)$%i', $value) or is_numeric($value)) {
2171
  $create_new_headers = true;
2172
  break;
2173
  }
2287
  }
2288
 
2289
  public function toXml() {
2290
+ $this->symmetrize();
2291
  return ArrayToXML::toXml($this->getRawArray());
2292
  }
2293
 
2413
  else
2414
  {
2415
  // add single node.
2416
+ $value = htmlspecialchars($value);
2417
  $xml->addChild($key,$value);
2418
  }
2419
 
libraries/XmlImportParser.php CHANGED
@@ -72,7 +72,7 @@ class XmlImportParser {
72
  throw new XmlImportException('Invalid root node XPath \'' . $this->rootNodeXPath . '\' specified');
73
 
74
  for ($i = 0; $i < count($rootNodes); $i++) {
75
- if (empty($records) or in_array(($i + 1) + 10 * $_SESSION['pmxi_import']['step'], $records)) {
76
  $rootNode = $rootNodes[$i];
77
  $template = new XmlImportTemplate($rootNode, $this->cachedTemplate);
78
  $result[] = $template->parse();
72
  throw new XmlImportException('Invalid root node XPath \'' . $this->rootNodeXPath . '\' specified');
73
 
74
  for ($i = 0; $i < count($rootNodes); $i++) {
75
+ if (empty($records) or in_array($i + 1, $records)) {
76
  $rootNode = $rootNodes[$i];
77
  $template = new XmlImportTemplate($rootNode, $this->cachedTemplate);
78
  $result[] = $template->parse();
libraries/XmlImportTemplateCodeGenerator.php CHANGED
@@ -17,6 +17,7 @@ require_once dirname(__FILE__) . '/ast/XmlImportAstWith.php';
17
  require_once dirname(__FILE__) . '/ast/XmlImportAstForeach.php';
18
  require_once dirname(__FILE__) . '/ast/XmlImportAstIf.php';
19
  require_once dirname(__FILE__) . '/ast/XmlImportAstMath.php';
 
20
 
21
  /**
22
  * Is used to generate a PHP code from AST (Abstract Syntax Tree)
@@ -127,7 +128,7 @@ class XmlImportTemplateCodeGenerator
127
  $result .= PHP_EOL;
128
  }
129
  foreach ($sequence->getStatements() as $statement)
130
- {
131
  $result .= $this->generateForStatement($statement);
132
  }
133
  array_pop($this->sequenceStack);
@@ -181,11 +182,11 @@ class XmlImportTemplateCodeGenerator
181
  ' as ' . $var . ') :' . PHP_EOL;
182
  array_push($this->xmlStack, $var);
183
  $result .= $this->generateForSequence($statement->getBody());
184
- $result .= $this->openPhpTag() . PHP_EOL . 'endforeach;' . PHP_EOL;
185
  array_pop($this->xmlStack);
186
  }
187
  elseif ($statement instanceof XmlImportAstIf)
188
- {
189
  $result .= PHP_EOL . 'if (' . $this->generateForExpression($statement->getCondition()) . ') :' . PHP_EOL;
190
  $result .= $this->generateForSequence($statement->getIfBody());
191
  foreach ($statement->getElseIfs() as $elseif)
@@ -198,7 +199,7 @@ class XmlImportTemplateCodeGenerator
198
  $result .= $this->openPhpTag() . PHP_EOL . 'else :' . PHP_EOL;
199
  $result .= $this->generateForSequence($body);
200
  }
201
- $result .= $this->openPhpTag() . PHP_EOL . 'endif;' . PHP_EOL;
202
  }
203
 
204
  }
@@ -242,9 +243,14 @@ class XmlImportTemplateCodeGenerator
242
 
243
  case 'XmlImportAstFunction':
244
  $result = $this->generateForFunction($expression);
245
- break;
246
- case 'XmlImportAstMath':
247
- $result = $this->generateForMath($expression);
 
 
 
 
 
248
  break;
249
  }
250
  return $result;
@@ -262,7 +268,7 @@ class XmlImportTemplateCodeGenerator
262
  $arguments = $function->getArguments();
263
  for($i = 0; $i < count($arguments); $i++)
264
  {
265
- $result .= $this->generateForExpression($arguments[$i]);
266
  if ($i < (count($arguments) - 1))
267
  $result .= ', ';
268
  }
@@ -289,6 +295,44 @@ class XmlImportTemplateCodeGenerator
289
  return 'number_format('.str_replace("\"", "", $result).',2)';
290
  }
291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  /**
293
  * Add PHP open tag if needed
294
  *
17
  require_once dirname(__FILE__) . '/ast/XmlImportAstForeach.php';
18
  require_once dirname(__FILE__) . '/ast/XmlImportAstIf.php';
19
  require_once dirname(__FILE__) . '/ast/XmlImportAstMath.php';
20
+ require_once dirname(__FILE__) . '/ast/XmlImportAstSpintax.php';
21
 
22
  /**
23
  * Is used to generate a PHP code from AST (Abstract Syntax Tree)
128
  $result .= PHP_EOL;
129
  }
130
  foreach ($sequence->getStatements() as $statement)
131
+ {
132
  $result .= $this->generateForStatement($statement);
133
  }
134
  array_pop($this->sequenceStack);
182
  ' as ' . $var . ') :' . PHP_EOL;
183
  array_push($this->xmlStack, $var);
184
  $result .= $this->generateForSequence($statement->getBody());
185
+ $result .= $this->openPhpTag() . PHP_EOL . 'endforeach;' . PHP_EOL;
186
  array_pop($this->xmlStack);
187
  }
188
  elseif ($statement instanceof XmlImportAstIf)
189
+ {
190
  $result .= PHP_EOL . 'if (' . $this->generateForExpression($statement->getCondition()) . ') :' . PHP_EOL;
191
  $result .= $this->generateForSequence($statement->getIfBody());
192
  foreach ($statement->getElseIfs() as $elseif)
199
  $result .= $this->openPhpTag() . PHP_EOL . 'else :' . PHP_EOL;
200
  $result .= $this->generateForSequence($body);
201
  }
202
+ $result .= $this->openPhpTag() . PHP_EOL . 'endif;' . PHP_EOL;
203
  }
204
 
205
  }
243
 
244
  case 'XmlImportAstFunction':
245
  $result = $this->generateForFunction($expression);
246
+ break;
247
+
248
+ case 'XmlImportAstMath':
249
+ $result = $this->generateForMath($expression);
250
+ break;
251
+
252
+ case 'XmlImportAstSpintax':
253
+ $result = $this->generateForSpintax($expression);
254
  break;
255
  }
256
  return $result;
268
  $arguments = $function->getArguments();
269
  for($i = 0; $i < count($arguments); $i++)
270
  {
271
+ $result .= $this->generateForExpression($arguments[$i], true);
272
  if ($i < (count($arguments) - 1))
273
  $result .= ', ';
274
  }
295
  return 'number_format('.str_replace("\"", "", $result).',2)';
296
  }
297
 
298
+ /**
299
+ * Generates code for a function
300
+ *
301
+ * @param XmlImportAstSpintax $expression
302
+ * @return string
303
+ */
304
+ private function generateForSpintax(XmlImportAstSpintax $spintax)
305
+ {
306
+ $result = '';
307
+ $arguments = $spintax->getArguments();
308
+
309
+ $spintax_begin = array();
310
+ $spintax_end = array();
311
+ $context = '';
312
+ $first_arg = true;
313
+ for ($i = 0; $i < count($arguments); $i++) {
314
+ if ($first_arg and $arguments[$i]['type'] == 'xpath') {
315
+ $spintax_begin[] = $this->generateForExpression($arguments[$i]['argument'], true);
316
+ }
317
+ elseif ($arguments[$i]['type'] == 'context')
318
+ {
319
+ $first_arg = false;
320
+ $context = $this->generateForExpression($arguments[$i]['argument'], true);
321
+ }
322
+ else
323
+ $spintax_end[] = $this->generateForExpression($arguments[$i]['argument'], true);
324
+ }
325
+
326
+ for($i = 0; $i < count($spintax_begin); $i++)
327
+ {
328
+ for ($j = 0; $j < count($spintax_end); $j++) {
329
+ $result .= '"<p>".'.$spintax_begin[$i].'."&nbsp;".'.$context.'."&nbsp;".'.$spintax_end[$j].'."</p>".';
330
+ }
331
+ }
332
+
333
+ return substr_replace($result ,"",-1);
334
+ }
335
+
336
  /**
337
  * Add PHP open tag if needed
338
  *
libraries/XmlImportTemplateParser.php CHANGED
@@ -11,6 +11,7 @@ require_once dirname(__FILE__) . '/ast/XmlImportAstWith.php';
11
  require_once dirname(__FILE__) . '/ast/XmlImportAstForeach.php';
12
  require_once dirname(__FILE__) . '/ast/XmlImportAstIf.php';
13
  require_once dirname(__FILE__) . '/ast/XmlImportAstMath.php';
 
14
 
15
  require_once dirname(__FILE__) . '/ast/XmlImportAstXPath.php';
16
  require_once dirname(__FILE__) . '/ast/XmlImportAstString.php';
@@ -146,10 +147,14 @@ class XmlImportTemplateParser
146
  {
147
  return $this->parseForeach();
148
  }
149
- elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
150
- {
151
- return new XmlImportAstPrint($this->parseExpression());
152
- }
 
 
 
 
153
  elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_IF)
154
  {
155
  return $this->parseIf();
@@ -185,12 +190,16 @@ class XmlImportTemplateParser
185
  {
186
  return $this->parseFunction();
187
  }
188
- elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
189
- {
190
- return $this->parseMath();
191
- }
192
- elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_XPATH)
193
  {
 
 
 
 
194
  $xpath = new XmlImportAstXPath($this->tokens[++$this->index]->getValue());
195
  $this->sequenceStack[count($this->sequenceStack) - 1]->addVariable($xpath);
196
  return $xpath;
@@ -283,6 +292,52 @@ class XmlImportTemplateParser
283
  }
284
  }
285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  /**
287
  * Parses clause that uses XPath and returns XPath
288
  *
11
  require_once dirname(__FILE__) . '/ast/XmlImportAstForeach.php';
12
  require_once dirname(__FILE__) . '/ast/XmlImportAstIf.php';
13
  require_once dirname(__FILE__) . '/ast/XmlImportAstMath.php';
14
+ require_once dirname(__FILE__) . '/ast/XmlImportAstSpintax.php';
15
 
16
  require_once dirname(__FILE__) . '/ast/XmlImportAstXPath.php';
17
  require_once dirname(__FILE__) . '/ast/XmlImportAstString.php';
147
  {
148
  return $this->parseForeach();
149
  }
150
+ elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
151
+ {
152
+ return new XmlImportAstPrint($this->parseExpression());
153
+ }
154
+ elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_SPINTAX)
155
+ {
156
+ return new XmlImportAstPrint($this->parseExpression());
157
+ }
158
  elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_IF)
159
  {
160
  return $this->parseIf();
190
  {
191
  return $this->parseFunction();
192
  }
193
+ elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_MATH)
194
+ {
195
+ return $this->parseMath();
196
+ }
197
+ elseif($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_SPINTAX)
198
  {
199
+ return $this->parseSpintax();
200
+ }
201
+ elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_XPATH)
202
+ {
203
  $xpath = new XmlImportAstXPath($this->tokens[++$this->index]->getValue());
204
  $this->sequenceStack[count($this->sequenceStack) - 1]->addVariable($xpath);
205
  return $xpath;
292
  }
293
  }
294
 
295
+ /**
296
+ * Parses function
297
+ *
298
+ * @return XmlImportSpintaxFunction
299
+ */
300
+ private function parseSpintax()
301
+ {
302
+ $spintax = new XmlImportAstSpintax($this->tokens[++$this->index]->getValue());
303
+ if ($this->tokens[$this->index + 1]->getKind() != XmlImportToken::KIND_OPEN)
304
+ throw new XmlImportException ("Open brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
305
+ $this->index++;
306
+ if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
307
+ {
308
+ $this->index++;
309
+ return $spintax;
310
+ }
311
+ else
312
+ {
313
+ while ($this->index < count($this->tokens) - 2)
314
+ {
315
+ if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_XPATH)
316
+ {
317
+ $xpath_parts = explode('|', str_replace(array('{', '}'), '', $this->tokens[++$this->index]->getValue()));
318
+ for ($i = 0; $i < count($xpath_parts); $i++) {
319
+ $xpath = new XmlImportAstXPath($xpath_parts[$i]);
320
+ $this->sequenceStack[count($this->sequenceStack) - 1]->addVariable($xpath);
321
+ $spintax->addArgument($xpath, 'xpath');
322
+ }
323
+ }
324
+ else $spintax->addArgument($this->parseExpression(), 'context');
325
+
326
+ if ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_CLOSE)
327
+ {
328
+ $this->index++;
329
+ return $spintax;
330
+ break;
331
+ }
332
+ elseif ($this->tokens[$this->index + 1]->getKind() == XmlImportToken::KIND_COMMA)
333
+ $this->index++;
334
+ else
335
+ throw new XmlImportException("Comma or closing brace expected instead of " . $this->tokens[$this->index + 1]->getKind());
336
+ }
337
+ throw new XmlImportException("Unexpected end of MATH argument list");
338
+ }
339
+ }
340
+
341
  /**
342
  * Parses clause that uses XPath and returns XPath
343
  *
libraries/XmlImportTemplateScanner.php CHANGED
@@ -26,7 +26,8 @@ final class XmlImportTemplateScanner
26
  'ENDFOREACH',
27
  'WITH',
28
  'ENDWITH',
29
- 'MATH'
 
30
  );
31
 
32
  /**
@@ -117,10 +118,10 @@ final class XmlImportTemplateScanner
117
  else
118
  $results[] = $result;
119
  }
120
- elseif ($ch == "+" || $ch == "-" || $ch == "/" || $ch == "*")
121
  {
122
  $this->isLangBegin = false;
123
- $input->read();
124
  $results[] = new XmlImportToken(XmlImportToken::KIND_OPERATION, $ch);
125
  }
126
  elseif ($ch == '"')
@@ -160,7 +161,7 @@ final class XmlImportTemplateScanner
160
  $input->read();
161
  $results[] = new XmlImportToken(XmlImportToken::KIND_COMMA);
162
  }
163
- elseif ($ch == ']')
164
  {
165
  $this->isLangBegin = false;
166
  $this->currentState = XmlImportTemplateScanner::STATE_TEXT;
26
  'ENDFOREACH',
27
  'WITH',
28
  'ENDWITH',
29
+ 'MATH',
30
+ 'SPINTAX'
31
  );
32
 
33
  /**
118
  else
119
  $results[] = $result;
120
  }
121
+ elseif ($ch == "+" || $ch == "-" || $ch == "*" || $ch == "/")
122
  {
123
  $this->isLangBegin = false;
124
+ $input->read();
125
  $results[] = new XmlImportToken(XmlImportToken::KIND_OPERATION, $ch);
126
  }
127
  elseif ($ch == '"')
161
  $input->read();
162
  $results[] = new XmlImportToken(XmlImportToken::KIND_COMMA);
163
  }
164
+ elseif ($ch == ']' or $ch == "|")
165
  {
166
  $this->isLangBegin = false;
167
  $this->currentState = XmlImportTemplateScanner::STATE_TEXT;
libraries/XmlImportToken.php CHANGED
@@ -117,6 +117,11 @@ class XmlImportToken
117
  * Token is a math on the price element
118
  */
119
  const KIND_MATH = "MATH";
 
 
 
 
 
120
 
121
  /**
122
  * Token is a math on the price element
117
  * Token is a math on the price element
118
  */
119
  const KIND_MATH = "MATH";
120
+
121
+ /**
122
+ * Token is a spintax
123
+ */
124
+ const KIND_SPINTAX = "SPINTAX";
125
 
126
  /**
127
  * Token is a math on the price element
libraries/ast/XmlImportAstSpintax.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @author Olexandr Zanichkovsky <olexandr.zanichkovsky@zophiatech.com>
4
+ * @package AST
5
+ */
6
+
7
+ require_once dirname(__FILE__) . '/XmlImportAstExpression.php';
8
+
9
+ /**
10
+ * Represents a function
11
+ */
12
+ class XmlImportAstSpintax extends XmlImportAstExpression
13
+ {
14
+ /**
15
+ * Function arguments
16
+ *
17
+ * @var array
18
+ */
19
+ private $arguments = array();
20
+
21
+ /**
22
+ * Creates new instance
23
+ *
24
+ * @param string $name
25
+ */
26
+ public function __construct($name)
27
+ {
28
+ $this->name = $name;
29
+ }
30
+
31
+ /**
32
+ * Adds argument to a function
33
+ *
34
+ * @param XmlImportAstExpression $argument
35
+ */
36
+ public function addArgument(XmlImportAstExpression $argument, $type = false)
37
+ {
38
+ $this->arguments[] = array(
39
+ 'argument' => $argument,
40
+ 'type' => $type
41
+ );
42
+ }
43
+
44
+ /**
45
+ * Gets function arguments
46
+ *
47
+ * @return array
48
+ */
49
+ public function getArguments()
50
+ {
51
+ return $this->arguments;
52
+ }
53
+
54
+ /**
55
+ * String representation of a function
56
+ *
57
+ * @return string
58
+ */
59
+ public function __toString()
60
+ {
61
+ $result = "--> begin " . get_class($this) . "\n";
62
+ foreach ($this->getArguments() as $argument)
63
+ {
64
+ $array = explode("\n", $argument);
65
+ for ($i = 0; $i < count($array); $i++)
66
+ {
67
+ $array[$i] = ' ' . $array[$i];
68
+ }
69
+ $result .= implode("\n", $array) . "\n";
70
+ }
71
+
72
+ $result .= "--> end " . get_class($this);
73
+
74
+ return $result;
75
+ }
76
+ }
models/import/record.php CHANGED
@@ -8,10 +8,18 @@ class PMXI_Import_Record extends PMXI_Model_Record {
8
  */
9
  public static function preprocessXml( & $xml) {
10
  //$xml = preg_replace('%\pC(?<!\s)%u', '', $xml); // remove control chars but not white-spacing ones
11
- //use HTML::Entities;
12
- $xml = preg_replace("/&.{0,}?;/",'',$xml);
 
 
13
  }
14
-
 
 
 
 
 
 
15
  /**
16
  * Validate XML to be valid for improt
17
  * @param string $xml
@@ -21,8 +29,11 @@ class PMXI_Import_Record extends PMXI_Model_Record {
21
  public static function validateXml( & $xml, $errors = NULL) {
22
  if (FALSE === $xml or '' == $xml) {
23
  $errors and $errors->add('form-validation', __('XML file does not exist, not accessible or empty', 'pmxi_plugin'));
24
- } else {
25
- if (PMXI_Plugin::getInstance()->getOption('html_entities')) PMXI_Import_Record::preprocessXml($xml);
 
 
 
26
  libxml_use_internal_errors(true);
27
  libxml_clear_errors();
28
  $_x = @simplexml_load_string($xml);
@@ -85,18 +96,77 @@ class PMXI_Import_Record extends PMXI_Model_Record {
85
  } else { // single file path
86
  $files = array($this->path);
87
  }
 
88
  foreach ($files as $ind => $path) {
89
  $logger and call_user_func($logger, sprintf(__('Importing %s (%s of %s)', 'pmxi_plugin'), $path, $ind + 1, count($files)));
 
 
 
 
 
 
90
 
91
- ob_start();
92
- readgzfile($path);
93
- $xml = ob_get_clean();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  if ( ! $xml) {
95
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': file is not accessible or empty');
96
  } elseif ( ! PMXI_Import_Record::validateXml($xml)) {
97
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': file is not a properly fromatted XML document');
98
  } else {
 
99
  $this->process($xml, $logger);
 
100
  }
101
  }
102
  $logger and call_user_func($logger, __('Complete', 'pmxi_plugin'));
@@ -111,12 +181,19 @@ class PMXI_Import_Record extends PMXI_Model_Record {
111
  * @return PMXI_Import_Record
112
  * @chainable
113
  */
114
- public function process($xml, $logger = NULL, $last_chank = false) {
115
  add_filter('user_has_cap', array($this, '_filter_has_cap_unfiltered_html')); kses_init(); // do not perform special filtering for imported content
116
 
117
- $this->options += PMXI_Plugin::get_default_import_options(); // make sure all options are defined
118
-
119
- $first_chank = $_SESSION['pmxi_import']['options']['is_first_chank'];
 
 
 
 
 
 
 
120
 
121
  $postRecord = new PMXI_Post_Record();
122
 
@@ -134,18 +211,18 @@ class PMXI_Import_Record extends PMXI_Model_Record {
134
  }
135
  try {
136
 
137
- $first_chank and $logger and call_user_func($logger, __('Composing contents...', 'pmxi_plugin'));
 
 
 
138
  $contents = XmlImportParser::factory(
139
  (intval($this->template['is_keep_linebreaks']) ? $xml : preg_replace('%\r\n?|\n%', ' ', $xml)),
140
  $this->xpath,
141
  $this->template['content'],
142
  $file)->parse($records
143
- ); $tmp_files[] = $file;
144
-
145
- $first_chank and $logger and call_user_func($logger, __('Composing titles...', 'pmxi_plugin'));
146
- $titles = XmlImportParser::factory($xml, $this->xpath, $this->template['title'], $file)->parse($records); $tmp_files[] = $file;
147
 
148
- $first_chank and $logger and call_user_func($logger, __('Composing dates...', 'pmxi_plugin'));
149
 
150
  $dates = XmlImportParser::factory($xml, $this->xpath, $this->options['date'], $file)->parse($records); $tmp_files[] = $file;
151
  $warned = array(); // used to prevent the same notice displaying several times
@@ -157,11 +234,11 @@ class PMXI_Import_Record extends PMXI_Model_Record {
157
  }
158
  $dates[$i] = date('Y-m-d H:i:s', $time);
159
  }
160
-
161
  if ('post' == $this->options['type']) {
162
  $tags = array();
163
  if ($this->options['tags']) {
164
- $first_chank and $logger and call_user_func($logger, __('Composing tags...', 'pmxi_plugin'));
165
  $tags_raw = XmlImportParser::factory($xml, $this->xpath, $this->options['tags'], $file)->parse($records); $tmp_files[] = $file;
166
  foreach ($tags_raw as $i => $t_raw) {
167
  $tags[$i] = '';
@@ -170,30 +247,50 @@ class PMXI_Import_Record extends PMXI_Model_Record {
170
  } else {
171
  count($titles) and $tags = array_fill(0, count($titles), '');
172
  }
 
173
  $cats = array();
174
- if ($this->options['categories']) {
175
- $first_chank and $logger and call_user_func($logger, __('Composing categories...', 'pmxi_plugin'));
176
- $cats_raw = XmlImportParser::factory($xml, $this->xpath, $this->options['categories'], $file)->parse($records); $tmp_files[] = $file;
 
 
 
 
 
 
 
 
177
  $warned = array(); // used to prevent the same notice displaying several times
178
  foreach ($cats_raw as $i => $c_raw) {
179
  $cats[$i] = array();
180
- if ('' != $c_raw) foreach (str_getcsv($c_raw, $this->options['categories_delim']) as $c) if ('' != $c) {
181
  $cat = get_term_by('name', $c, 'category') or ctype_digit($c) and $cat = get_term_by('id', $c, 'category');
182
  if ( ! $cat) { // create category automatically
183
- $cat_id = wp_create_category($c);
184
- if ( ! $cat_id) {
185
- in_array($c, $warned) or $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to create category `%s`, skipping', 'pmxi_plugin'), $warned[] = $c));
186
- } else {
187
- $cats[$i][] = $cat_id;
 
 
 
 
 
 
 
 
 
 
 
188
  }
189
  } else {
190
  $cats[$i][] = $cat->term_id;
191
  }
192
  }
193
- }
194
  } else {
195
  count($titles) and $cats = array_fill(0, count($titles), '');
196
- }
197
  }
198
  // [custom taxonomies]
199
  $taxonomies = array();
@@ -205,71 +302,113 @@ class PMXI_Import_Record extends PMXI_Model_Record {
205
  } else {
206
  $taxonomies_object_type = 'post';
207
  }
208
- foreach ($this->options[$taxonomies_param] as $tx_name => $tx_template) if ('' != $tx_template) {
209
  $tx = get_taxonomy($tx_name);
210
  if (in_array($taxonomies_object_type, $tx->object_type)) {
211
- $first_chank and $logger and call_user_func($logger, sprintf(__('Composing terms for `%s` taxonomy...', 'pmxi_plugin'), $tx->labels->name));
212
  $txes = array();
213
- $txes_raw = XmlImportParser::factory($xml, $this->xpath, $tx_template, $file)->parse($records); $tmp_files[] = $file;
 
 
 
 
 
214
  foreach ($txes_raw as $i => $tx_raw) {
215
- $taxonomies[$tx_name][$i] = str_getcsv($tx_raw, $this->options[$taxonomies_param.'_delim'][$tx_name]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  }
217
  }
218
- }
219
  // [/custom taxonomies]
220
 
221
- $first_chank and $logger and call_user_func($logger, __('Composing custom parameters...', 'pmxi_plugin'));
222
  $meta_keys = array(); $meta_values = array();
223
  foreach ($this->options['custom_name'] as $j => $custom_name) {
224
  $meta_keys[$j] = XmlImportParser::factory($xml, $this->xpath, $custom_name, $file)->parse($records); $tmp_files[] = $file;
225
  $meta_values[$j] = XmlImportParser::factory($xml, $this->xpath, $this->options['custom_value'][$j], $file)->parse($records); $tmp_files[] = $file;
226
- }
 
 
 
 
 
 
 
 
 
 
 
 
227
  if ( ! (($uploads = wp_upload_dir()) && false === $uploads['error'])) {
228
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': ' . $uploads['error']);
229
  $logger and call_user_func($logger, __('<b>WARNING</b>: No featured images will be created', 'pmxi_plugin'));
230
  } else {
231
- $first_chank and $logger and call_user_func($logger, __('Composing URLs for featured images...', 'pmxi_plugin'));
232
  $featured_images = array();
233
  if ($this->options['featured_image']) {
234
  // Detect if images is separated by comma
235
- $imgs = explode(',',$this->options['featured_image']);
236
  if (!empty($imgs)){
237
  $parse_multiple = true;
238
- foreach($imgs as $img) if (!preg_match("/{.*}/", trim($img))) $parse_multiple = false;
 
239
  if ($parse_multiple)
240
  {
241
  foreach($imgs as $img)
242
- {
243
- $posts_images = XmlImportParser::factory($xml, $this->xpath, $img, $file)->parse($records); $tmp_files[] = $file;
244
- foreach($posts_images as $i => $val)
245
- {
246
- $reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,4}(\/\S*)?/";
247
- preg_match_all($reg_exUrl, $val, $matches);
248
- $usedPatterns = array();
249
- foreach($matches[0] as $pattern){
250
- if(!array_key_exists($pattern, $usedPatterns)){
251
- $usedPatterns[$pattern]=true;
252
- $featured_images[$i][] = str_replace(',','',$pattern);
253
- }
254
- }
255
- }
256
-
257
  }
258
  }
259
  else
260
  {
261
- $featured_images = XmlImportParser::factory($xml, $this->xpath, $this->options['featured_image'], $file)->parse($records); $tmp_files[] = $file;
262
  }
263
  }
264
 
265
  } else {
266
  count($titles) and $featured_images = array_fill(0, count($titles), '');
267
  }
268
- }
269
- $first_chank and $logger and call_user_func($logger, __('Composing unique keys...', 'pmxi_plugin'));
270
  $unique_keys = XmlImportParser::factory($xml, $this->xpath, $this->options['unique_key'], $file)->parse($records); $tmp_files[] = $file;
271
 
272
- $first_chank and $logger and call_user_func($logger, __('Processing posts...', 'pmxi_plugin'));
273
 
274
  if ('post' == $this->options['type'] and '' != $this->options['custom_type']) {
275
  $post_type = $this->options['custom_type'];
@@ -311,6 +450,7 @@ class PMXI_Import_Record extends PMXI_Model_Record {
311
  $post_to_update = get_post($post_to_update_id = $postRecord->post_id);
312
  if ($post_to_update) { // existing post is found
313
  if ($this->options['is_keep_former_posts']) {
 
314
  $logger and call_user_func($logger, sprintf(__('<b>SKIPPED</b>: Previously imported record found for `%s`', 'pmxi_plugin'), $articleData['post_title']));
315
  continue;
316
  }
@@ -357,6 +497,9 @@ class PMXI_Import_Record extends PMXI_Model_Record {
357
  if ($this->options['is_keep_status']) { // preserve status and trashed flag
358
  $articleData['post_status'] = $post_to_update->post_status;
359
  }
 
 
 
360
  } else { // existing post not found though it's track was found... clear the leftover, plugin will continue to treat record as new
361
  $postRecord->delete();
362
  }
@@ -445,13 +588,16 @@ class PMXI_Import_Record extends PMXI_Model_Record {
445
  if (is_wp_error($pid)) {
446
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': ' . $pid->get_error_message());
447
  } else {
 
 
 
448
  $current_post_ids[] = $pid;
449
  // associate post with import
450
  $postRecord->isEmpty() and $postRecord->set(array(
451
  'post_id' => $pid,
452
  'import_id' => $this->id,
453
  'unique_key' => $unique_keys[$i],
454
- ))->insert();
455
 
456
  // [custom taxonomies]
457
  foreach ($taxonomies as $tx_name => $txes) {
@@ -482,9 +628,9 @@ class PMXI_Import_Record extends PMXI_Model_Record {
482
  } catch (XmlImportException $e) {
483
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': ' . $e->getMessage());
484
  }
485
- $last_chank and $this->set('registered_on', date('Y-m-d H:i:s'))->save(); // specify execution is successful
486
 
487
- $last_chank and $logger and call_user_func($logger, __('Cleaning temporary data...', 'pmxi_plugin'));
488
  foreach ($tmp_files as $file) { // remove all temporary files created
489
  unlink($file);
490
  }
@@ -495,12 +641,43 @@ class PMXI_Import_Record extends PMXI_Model_Record {
495
  $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to remove %s', 'pmxi_plugin'), $this->path));
496
  }
497
  }
498
- $logger and $last_chank and call_user_func($logger, 'Done');
499
 
500
  remove_filter('user_has_cap', array($this, '_filter_has_cap_unfiltered_html')); kses_init(); // return any filtering rules back if they has been disabled for import procedure
501
 
502
  return $this;
503
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
 
505
  public function _filter_has_cap_unfiltered_html($caps)
506
  {
8
  */
9
  public static function preprocessXml( & $xml) {
10
  //$xml = preg_replace('%\pC(?<!\s)%u', '', $xml); // remove control chars but not white-spacing ones
11
+ //use HTML::Entities;
12
+
13
+ $xml = preg_replace("/&.{0,}?;/",'',$xml);
14
+
15
  }
16
+
17
+ public static function uft8decodeXml( & $xml ){
18
+
19
+ $xml = str_replace(array("&"), array("&amp;"), utf8_decode($xml));
20
+
21
+ }
22
+
23
  /**
24
  * Validate XML to be valid for improt
25
  * @param string $xml
29
  public static function validateXml( & $xml, $errors = NULL) {
30
  if (FALSE === $xml or '' == $xml) {
31
  $errors and $errors->add('form-validation', __('XML file does not exist, not accessible or empty', 'pmxi_plugin'));
32
+ } else {
33
+
34
+ if (PMXI_Plugin::getInstance()->getOption('utf8_decode')) PMXI_Import_Record::uft8decodeXml($xml);
35
+ if (PMXI_Plugin::getInstance()->getOption('html_entities')) PMXI_Import_Record::preprocessXml($xml);
36
+
37
  libxml_use_internal_errors(true);
38
  libxml_clear_errors();
39
  $_x = @simplexml_load_string($xml);
96
  } else { // single file path
97
  $files = array($this->path);
98
  }
99
+
100
  foreach ($files as $ind => $path) {
101
  $logger and call_user_func($logger, sprintf(__('Importing %s (%s of %s)', 'pmxi_plugin'), $path, $ind + 1, count($files)));
102
+
103
+ $contents = get_headers($path,1 );
104
+
105
+ if (preg_match('%\W(zip)$%i', trim($path))){
106
+
107
+ $uploads = wp_upload_dir();
108
 
109
+ $newfile = $uploads['path']."/".md5(time()).'.zip';
110
+
111
+ if (!copy($path, $newfile)) {
112
+ $this->errors->add('form-validation', __('Failed upload ZIP archive', 'pmxi_plugin'));
113
+ }
114
+
115
+ $zip = zip_open($newfile);
116
+ if (is_resource($zip)) {
117
+ $uploads = wp_upload_dir();
118
+ if($uploads['error']){
119
+ $this->errors->add('form-validation', __('Can not create upload folder. Permision denied', 'pmxi_plugin'));
120
+ }
121
+ $filename = '';
122
+ while ($zip_entry = zip_read($zip)) {
123
+ $filename = zip_entry_name($zip_entry);
124
+ $fp = fopen($uploads['path']."/".$filename, "w");
125
+ if (zip_entry_open($zip, $zip_entry, "r")) {
126
+ $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
127
+ fwrite($fp,"$buf");
128
+ zip_entry_close($zip_entry);
129
+ fclose($fp);
130
+ }
131
+ break;
132
+ }
133
+ zip_close($zip);
134
+ unlink($newfile);
135
+ if (preg_match('%\W(csv)$%i', trim($filename)) or PMXI_Plugin::detect_csv($contents['Content-Type']))
136
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] .'/'. $filename);
137
+ else
138
+ $xml = @file_get_contents($uploads['path'] .'/'. $filename);
139
+ }
140
+
141
+ } elseif (preg_match('%\W(csv)$%i', trim($path)) or PMXI_Plugin::detect_csv($contents['Content-Type'])) {
142
+ $uploads = wp_upload_dir();
143
+ $fdata = file_get_contents($path);
144
+ $fdata = utf8_encode($fdata);
145
+ $tmpname = md5(time()).'.csv';
146
+ file_put_contents($uploads['path'] .'/'. $tmpname, $fdata);
147
+ $xml = PMXI_Plugin::csv_to_xml($uploads['path'] .'/'. $tmpname);
148
+ }
149
+ else
150
+ {
151
+ ob_start();
152
+ readgzfile($path);
153
+ $xml = ob_get_clean();
154
+
155
+ $wp_uploads = wp_upload_dir();
156
+ $url = $wp_uploads['url'] .'/'. basename($path);
157
+ file_put_contents($wp_uploads['path'] .'/'. basename($path), $xml);
158
+ chmod($wp_uploads['path'] .'/'. basename($path), '0755');
159
+
160
+ if ($contents = get_headers($url,1 ) and PMXI_Plugin::detect_csv($contents['Content-Type'])) $xml = PMXI_Plugin::csv_to_xml($wp_uploads['path']. basename($path));
161
+ }
162
  if ( ! $xml) {
163
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': file is not accessible or empty');
164
  } elseif ( ! PMXI_Import_Record::validateXml($xml)) {
165
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': file is not a properly fromatted XML document');
166
  } else {
167
+ do_action( 'pmxi_before_xml_import' );
168
  $this->process($xml, $logger);
169
+ do_action( 'pmxi_after_xml_import' );
170
  }
171
  }
172
  $logger and call_user_func($logger, __('Complete', 'pmxi_plugin'));
181
  * @return PMXI_Import_Record
182
  * @chainable
183
  */
184
+ public function process($xml, $logger = NULL) {
185
  add_filter('user_has_cap', array($this, '_filter_has_cap_unfiltered_html')); kses_init(); // do not perform special filtering for imported content
186
 
187
+ $this->options += PMXI_Plugin::get_default_import_options(); // make sure all options are defined
188
+
189
+ $history_file = new PMXI_File_Record();
190
+ $history_file->set(array(
191
+ 'name' => $this->name,
192
+ 'import_id' => $this->id,
193
+ 'path' => $this->path,
194
+ 'contents' => $xml,
195
+ 'registered_on' => date('Y-m-d H:i:s'),
196
+ ))->save();
197
 
198
  $postRecord = new PMXI_Post_Record();
199
 
211
  }
212
  try {
213
 
214
+ $logger and call_user_func($logger, __('Composing titles...', 'pmxi_plugin'));
215
+ $titles = XmlImportParser::factory($xml, $this->xpath, $this->template['title'], $file)->parse($records); $tmp_files[] = $file;
216
+
217
+ $logger and call_user_func($logger, __('Composing contents...', 'pmxi_plugin'));
218
  $contents = XmlImportParser::factory(
219
  (intval($this->template['is_keep_linebreaks']) ? $xml : preg_replace('%\r\n?|\n%', ' ', $xml)),
220
  $this->xpath,
221
  $this->template['content'],
222
  $file)->parse($records
223
+ ); $tmp_files[] = $file;
 
 
 
224
 
225
+ $logger and call_user_func($logger, __('Composing dates...', 'pmxi_plugin'));
226
 
227
  $dates = XmlImportParser::factory($xml, $this->xpath, $this->options['date'], $file)->parse($records); $tmp_files[] = $file;
228
  $warned = array(); // used to prevent the same notice displaying several times
234
  }
235
  $dates[$i] = date('Y-m-d H:i:s', $time);
236
  }
237
+
238
  if ('post' == $this->options['type']) {
239
  $tags = array();
240
  if ($this->options['tags']) {
241
+ $logger and call_user_func($logger, __('Composing tags...', 'pmxi_plugin'));
242
  $tags_raw = XmlImportParser::factory($xml, $this->xpath, $this->options['tags'], $file)->parse($records); $tmp_files[] = $file;
243
  foreach ($tags_raw as $i => $t_raw) {
244
  $tags[$i] = '';
247
  } else {
248
  count($titles) and $tags = array_fill(0, count($titles), '');
249
  }
250
+
251
  $cats = array();
252
+
253
+ $categories_hierarchy = (!empty($this->options['categories'])) ? json_decode($this->options['categories']) : array();
254
+
255
+ if ((!empty($categories_hierarchy) and is_array($categories_hierarchy))){
256
+
257
+ $logger and call_user_func($logger, __('Composing categories...', 'pmxi_plugin'));
258
+ $categories = array();
259
+
260
+ foreach ($categories_hierarchy as $category) $categories[] = $category->xpath;
261
+
262
+ $cats_raw = XmlImportParser::factory($xml, $this->xpath, ((!empty($categories)) ? implode(',', $categories) : ''), $file)->parse($records); $tmp_files[] = $file;
263
  $warned = array(); // used to prevent the same notice displaying several times
264
  foreach ($cats_raw as $i => $c_raw) {
265
  $cats[$i] = array();
266
+ if ('' != $c_raw) foreach (str_getcsv($c_raw, ',') as $j => $c) if ('' != $c) {
267
  $cat = get_term_by('name', $c, 'category') or ctype_digit($c) and $cat = get_term_by('id', $c, 'category');
268
  if ( ! $cat) { // create category automatically
269
+ if (!empty($categories_hierarchy[$j]->parent_id)) {
270
+ $parent_id = $this->reverse_hierarchy($categories_hierarchy, $c_raw, $categories_hierarchy[$j]->parent_id, $warned);
271
+ $cat_id = wp_create_category($c, $parent_id);
272
+ if ( ! $cat_id) {
273
+ in_array($c, $warned) or $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to create category `%s`, skipping', 'pmxi_plugin'), $warned[] = $c));
274
+ } else {
275
+ $cats[$i][] = $cat_id;
276
+ }
277
+ }
278
+ else {
279
+ $cat_id = wp_create_category($c);
280
+ if ( ! $cat_id) {
281
+ in_array($c, $warned) or $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to create category `%s`, skipping', 'pmxi_plugin'), $warned[] = $c));
282
+ } else {
283
+ $cats[$i][] = $cat_id;
284
+ }
285
  }
286
  } else {
287
  $cats[$i][] = $cat->term_id;
288
  }
289
  }
290
+ }
291
  } else {
292
  count($titles) and $cats = array_fill(0, count($titles), '');
293
+ }
294
  }
295
  // [custom taxonomies]
296
  $taxonomies = array();
302
  } else {
303
  $taxonomies_object_type = 'post';
304
  }
305
+ if (!empty($this->options[$taxonomies_param]) and is_array($this->options[$taxonomies_param])): foreach ($this->options[$taxonomies_param] as $tx_name => $tx_template) if ('' != $tx_template) {
306
  $tx = get_taxonomy($tx_name);
307
  if (in_array($taxonomies_object_type, $tx->object_type)) {
308
+ $logger and call_user_func($logger, sprintf(__('Composing terms for `%s` taxonomy...', 'pmxi_plugin'), $tx->labels->name));
309
  $txes = array();
310
+
311
+ $taxonomies_hierarchy = json_decode($tx_template);
312
+ foreach ($taxonomies_hierarchy as $taxonomy) $txes[] = $taxonomy->xpath;
313
+
314
+ $txes_raw = XmlImportParser::factory($xml, $this->xpath, ((!empty($txes)) ? implode(',', $txes) : ''), $file)->parse($records); $tmp_files[] = $file;
315
+ $warned = array();
316
  foreach ($txes_raw as $i => $tx_raw) {
317
+ $taxonomies[$tx_name][$i] = array();
318
+ if ('' != $tx_raw) foreach (str_getcsv($tx_raw, ',') as $j => $c) if ('' != $c) {
319
+ $cat = get_term_by('name', $c, $tx_name) or ctype_digit($c) and $cat = get_term_by('id', $c, $tx_name);
320
+ if ( ! $cat) { // create taxonomy automatically
321
+ if (!empty($taxonomies_hierarchy[$j]->parent_id)) {
322
+ $parent_term_id = $this->reverse_hierarchy($taxonomies_hierarchy, $tx_raw, $taxonomies_hierarchy[$j]->parent_id, $warned);
323
+
324
+ $term = wp_insert_term(
325
+ $c, // the term
326
+ $tx_name, // the taxonomy
327
+ array(
328
+ 'parent'=> $parent_term_id
329
+ )
330
+ );
331
+ $cat_id = $term['term_id'];
332
+ if ( ! $cat_id) {
333
+ in_array($c, $warned) or $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to create category `%s`, skipping', 'pmxi_plugin'), $warned[] = $c));
334
+ } else {
335
+ $taxonomies[$tx_name][$i][] = $c;
336
+ }
337
+ }
338
+ else {
339
+ $term = wp_insert_term(
340
+ $c, // the term
341
+ $tx_name // the taxonomy
342
+ );
343
+ $cat_id = $term['term_id'];
344
+ if ( ! $cat_id) {
345
+ in_array($c, $warned) or $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to create category `%s`, skipping', 'pmxi_plugin'), $warned[] = $c));
346
+ } else {
347
+ $taxonomies[$tx_name][$i][] = $c;
348
+ }
349
+ }
350
+ } else {
351
+ $taxonomies[$tx_name][$i][] = $cat->name;
352
+ }
353
+ }
354
  }
355
  }
356
+ }; endif;
357
  // [/custom taxonomies]
358
 
359
+ $logger and call_user_func($logger, __('Composing custom parameters...', 'pmxi_plugin'));
360
  $meta_keys = array(); $meta_values = array();
361
  foreach ($this->options['custom_name'] as $j => $custom_name) {
362
  $meta_keys[$j] = XmlImportParser::factory($xml, $this->xpath, $custom_name, $file)->parse($records); $tmp_files[] = $file;
363
  $meta_values[$j] = XmlImportParser::factory($xml, $this->xpath, $this->options['custom_value'][$j], $file)->parse($records); $tmp_files[] = $file;
364
+ }
365
+ // serialized custom post fields
366
+ $serialized_meta = array();
367
+ if (!empty($meta_keys)){
368
+ foreach ($meta_keys as $j => $custom_name) {
369
+ if (!in_array($custom_name[0], array_keys($serialized_meta))){
370
+ $serialized_meta[$custom_name[0]] = array($meta_values[$j]);
371
+ }
372
+ else{
373
+ $serialized_meta[$custom_name[0]][] = $meta_values[$j];
374
+ }
375
+ }
376
+ }
377
  if ( ! (($uploads = wp_upload_dir()) && false === $uploads['error'])) {
378
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': ' . $uploads['error']);
379
  $logger and call_user_func($logger, __('<b>WARNING</b>: No featured images will be created', 'pmxi_plugin'));
380
  } else {
381
+ $logger and call_user_func($logger, __('Composing URLs for featured images...', 'pmxi_plugin'));
382
  $featured_images = array();
383
  if ($this->options['featured_image']) {
384
  // Detect if images is separated by comma
385
+ $imgs = explode(',',$this->options['featured_image']);
386
  if (!empty($imgs)){
387
  $parse_multiple = true;
388
+ foreach($imgs as $img) if (!preg_match("/{.*}/", trim($img))) $parse_multiple = false;
389
+
390
  if ($parse_multiple)
391
  {
392
  foreach($imgs as $img)
393
+ {
394
+ $posts_images = XmlImportParser::factory($xml, $this->xpath, trim($img), $file)->parse($records); $tmp_files[] = $file;
395
+ foreach($posts_images as $i => $val) $featured_images[$i][] = $val;
 
 
 
 
 
 
 
 
 
 
 
 
396
  }
397
  }
398
  else
399
  {
400
+ $featured_images = XmlImportParser::factory($xml, $this->xpath, $this->options['featured_image'], $file)->parse($records); $tmp_files[] = $file;
401
  }
402
  }
403
 
404
  } else {
405
  count($titles) and $featured_images = array_fill(0, count($titles), '');
406
  }
407
+ }
408
+ $logger and call_user_func($logger, __('Composing unique keys...', 'pmxi_plugin'));
409
  $unique_keys = XmlImportParser::factory($xml, $this->xpath, $this->options['unique_key'], $file)->parse($records); $tmp_files[] = $file;
410
 
411
+ $logger and call_user_func($logger, __('Processing posts...', 'pmxi_plugin'));
412
 
413
  if ('post' == $this->options['type'] and '' != $this->options['custom_type']) {
414
  $post_type = $this->options['custom_type'];
450
  $post_to_update = get_post($post_to_update_id = $postRecord->post_id);
451
  if ($post_to_update) { // existing post is found
452
  if ($this->options['is_keep_former_posts']) {
453
+ $current_post_ids[] = $postRecord->post_id;
454
  $logger and call_user_func($logger, sprintf(__('<b>SKIPPED</b>: Previously imported record found for `%s`', 'pmxi_plugin'), $articleData['post_title']));
455
  continue;
456
  }
497
  if ($this->options['is_keep_status']) { // preserve status and trashed flag
498
  $articleData['post_status'] = $post_to_update->post_status;
499
  }
500
+ if ($this->options['is_keep_content']){ // Re-run an importer to pull in one more custom field... without nuking their edits in the process..
501
+ $articleData['post_content'] = $post_to_update->post_content;
502
+ }
503
  } else { // existing post not found though it's track was found... clear the leftover, plugin will continue to treat record as new
504
  $postRecord->delete();
505
  }
588
  if (is_wp_error($pid)) {
589
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': ' . $pid->get_error_message());
590
  } else {
591
+
592
+ do_action( 'pmxi_saved_post', $pid); // hook that was triggered immediately after post saved
593
+
594
  $current_post_ids[] = $pid;
595
  // associate post with import
596
  $postRecord->isEmpty() and $postRecord->set(array(
597
  'post_id' => $pid,
598
  'import_id' => $this->id,
599
  'unique_key' => $unique_keys[$i],
600
+ ))->insert();
601
 
602
  // [custom taxonomies]
603
  foreach ($taxonomies as $tx_name => $txes) {
628
  } catch (XmlImportException $e) {
629
  $logger and call_user_func($logger, __('<b>ERROR</b>', 'pmxi_plugin') . ': ' . $e->getMessage());
630
  }
631
+ $this->set('registered_on', date('Y-m-d H:i:s'))->save(); // specify execution is successful
632
 
633
+ $logger and call_user_func($logger, __('Cleaning temporary data...', 'pmxi_plugin'));
634
  foreach ($tmp_files as $file) { // remove all temporary files created
635
  unlink($file);
636
  }
641
  $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to remove %s', 'pmxi_plugin'), $this->path));
642
  }
643
  }
644
+ $logger and call_user_func($logger, 'Done');
645
 
646
  remove_filter('user_has_cap', array($this, '_filter_has_cap_unfiltered_html')); kses_init(); // return any filtering rules back if they has been disabled for import procedure
647
 
648
  return $this;
649
  }
650
+
651
+ public function reverse_hierarchy($categories_hierarchy, $c_raw, $parent_id = null, &$warned, $taxonomy = 'category'){
652
+ foreach (str_getcsv($c_raw, ',') as $j => $c) if ('' != $c and $categories_hierarchy[$j]->item_id == $parent_id) {
653
+ $cat = get_term_by('name', $c, $taxonomy) or ctype_digit($c) and $cat = get_term_by('id', $c, $taxonomy);
654
+ if ( ! $cat) { // create category automatically
655
+ if (!empty($categories_hierarchy[$j]->parent_id)) {
656
+ return $this->reverse_hierarchy($categories_hierarchy, $c_raw, $categories_hierarchy[$j]->parent_id, $warned, $taxonomy);
657
+ }
658
+ else {
659
+ if ($taxonomy == 'category')
660
+ {
661
+ $cat_id = wp_create_category($c);
662
+ }
663
+ else{
664
+ $term = wp_insert_term(
665
+ $c,
666
+ $taxonomy
667
+ );
668
+ $cat_id = $term['term_id'];
669
+ }
670
+ if ( ! $cat_id) {
671
+ in_array($c, $warned) or $logger and call_user_func($logger, sprintf(__('<b>WARNING</b>: Unable to create category `%s`, skipping', 'pmxi_plugin'), $warned[] = $c));
672
+ } else {
673
+ return $cat_id;
674
+ }
675
+ }
676
+ } else {
677
+ return $cat->term_id;
678
+ }
679
+ }
680
+ }
681
 
682
  public function _filter_has_cap_unfiltered_html($caps)
683
  {
plugin.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: WP All Import
4
  Plugin URI: http://www.wpallimport.com/upgrade-to-pro
5
  Description: The most powerful solution for importing XML and CSV files to WordPress. Create Posts and Pages with content from any XML or CSV file. Perform scheduled updates and overwrite of existing import jobs. Free lite edition.
6
- Version: 2.13
7
  Author: Soflyy
8
  */
9
  /**
3
  Plugin Name: WP All Import
4
  Plugin URI: http://www.wpallimport.com/upgrade-to-pro
5
  Description: The most powerful solution for importing XML and CSV files to WordPress. Create Posts and Pages with content from any XML or CSV file. Perform scheduled updates and overwrite of existing import jobs. Free lite edition.
6
+ Version: 2.14
7
  Author: Soflyy
8
  */
9
  /**
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: soflyy
3
  Tags: wordpress, xml, csv, datafeed, import
4
  Requires at least: 3.0
5
  Tested up to: 3.4.2
6
- Stable tag: 2.13
7
 
8
- The most powerful tool for importing any CSV or XML feed to WordPress.
9
 
10
  == Description ==
11
 
@@ -65,6 +65,9 @@ Use pretty much any delimiter you want. It has to work with the [fgetcsv](http:/
65
 
66
  == Changelog ==
67
 
 
 
 
68
  = 2.13 =
69
  * Tons of bug fixes, updates, and additional features.
70
 
3
  Tags: wordpress, xml, csv, datafeed, import
4
  Requires at least: 3.0
5
  Tested up to: 3.4.2
6
+ Stable tag: 2.14
7
 
8
+ The most powerful tool for importing any CSV or XML feed to WordPress. --tag
9
 
10
  == Description ==
11
 
65
 
66
  == Changelog ==
67
 
68
+ = 2.14 =
69
+ * Category list delimiter bug fix
70
+
71
  = 2.13 =
72
  * Tons of bug fixes, updates, and additional features.
73
 
schema.php CHANGED
@@ -48,10 +48,11 @@ CREATE TABLE {$table_prefix}imports (
48
  PRIMARY KEY (id)
49
  ) $charset_collate;
50
  CREATE TABLE {$table_prefix}posts (
 
51
  post_id BIGINT(20) UNSIGNED NOT NULL,
52
  import_id BIGINT(20) UNSIGNED NOT NULL,
53
  unique_key TEXT,
54
- PRIMARY KEY (post_id)
55
  ) $charset_collate;
56
  CREATE TABLE {$table_prefix}files (
57
  id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
48
  PRIMARY KEY (id)
49
  ) $charset_collate;
50
  CREATE TABLE {$table_prefix}posts (
51
+ id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
52
  post_id BIGINT(20) UNSIGNED NOT NULL,
53
  import_id BIGINT(20) UNSIGNED NOT NULL,
54
  unique_key TEXT,
55
+ PRIMARY KEY (id)
56
  ) $charset_collate;
57
  CREATE TABLE {$table_prefix}files (
58
  id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
screenshot-1.png ADDED
Binary file
screenshot-2.png ADDED
Binary file
screenshot-3.png ADDED
Binary file
screenshot-4.png ADDED
Binary file
static/css/admin.css CHANGED
@@ -225,6 +225,8 @@
225
  }
226
  .pmxi_plugin .post-type-options table.form-table td.delim {
227
  width: 50px;
 
 
228
  }
229
  .pmxi_plugin .post-type-options table.form-table td.delim input {
230
  width: 20px;
@@ -466,4 +468,37 @@ table.xml table {
466
  .pmxi_plugin form.options table.layout td.right{
467
  position: fixed;
468
  width: 25%;
469
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  }
226
  .pmxi_plugin .post-type-options table.form-table td.delim {
227
  width: 50px;
228
+ position: relative;
229
+ display: block;
230
  }
231
  .pmxi_plugin .post-type-options table.form-table td.delim input {
232
  width: 20px;
468
  .pmxi_plugin form.options table.layout td.right{
469
  position: fixed;
470
  width: 25%;
471
+ }
472
+ .pmxi_plugin .drag-element{
473
+ background: url("../img/drag.png") top right no-repeat;
474
+ cursor: pointer;
475
+ padding-right: 25px;
476
+ background-position: 100% 1px;
477
+ }
478
+ .sortable li{ position: relative;}
479
+ .pmxi_plugin ol{
480
+ margin-top: 6px;
481
+ list-style: none;
482
+ }
483
+ .pmxi_plugin .no-margin{ margin:0px; }
484
+ .pmxi_plugin .icon-item{
485
+ display: inline-block;;
486
+ width: 16px;
487
+ height: 16px;
488
+ margin: 0px 3px;
489
+ }
490
+ .pmxi_plugin .add-new-ico{
491
+ background: url("../img/ico-add-new.png") no-repeat;
492
+ position: absolute;
493
+ top:5px;
494
+ right: 0px;
495
+ }
496
+
497
+ .pmxi_plugin .remove-ico{
498
+ background: url("../img/ico-remove.png") no-repeat;
499
+ top:1px;
500
+ right:-30px;
501
+ position: absolute;
502
+ }
503
+
504
+ .pmxi_plugin .hidden{ display: none; }
static/img/drag.png ADDED
Binary file
static/img/ico-add-new.png ADDED
Binary file
static/img/ico-remove.png ADDED
Binary file
static/js/admin.js CHANGED
@@ -109,7 +109,7 @@
109
  // choose file form: option selection dynamic
110
  // options form: highlight options of selected post type
111
  $('form.choose-file input[name="type"]').click(function() {
112
- var $container = $(this).parents('.file-type-container');
113
  $('.file-type-container').not($container).removeClass('selected').find('.file-type-options').hide();
114
  $container.addClass('selected').find('.file-type-options').show();
115
  }).filter(':checked').click();
@@ -171,6 +171,16 @@
171
  'value':''
172
  };
173
 
 
 
 
 
 
 
 
 
 
 
174
  // [xml representation dynamic]
175
  $.fn.xml = function (opt) {
176
  if ( ! this.length) return this;
@@ -255,16 +265,7 @@
255
  $('.xml-element[title*="/'+$(this).val().replace('{','').replace('}','')+'"]').addClass('selected');
256
  }
257
  });
258
-
259
- var insertxpath = function(){
260
- if (dblclickbuf.selected)
261
- {
262
- $(this).val($(this).val() + dblclickbuf.value);
263
- $('.xml-element[title*="/'+dblclickbuf.value.replace('{','').replace('}','')+'"]').removeClass('selected');
264
- dblclickbuf.value = '';
265
- dblclickbuf.selected = false;
266
- }
267
- }
268
  $('#title, #content, .widefat, input[name^=custom_name], textarea[name^=custom_value], input[name^=featured_image], input[name^=unique_key]').bind('focus', insertxpath );
269
 
270
  $(document).mousemove(function () {
@@ -357,65 +358,43 @@
357
  });
358
  });
359
 
360
- function process(first_chank, update_previous){
361
- $('input[name=is_first_chank],input[name=is_update_previous]').remove();
362
- $("form").append('<input type="hidden" name="is_first_chank" value="'+((first_chank) ? 1 : 0)+'"/>');
363
- $("form").append('<input type="hidden" name="is_update_previous" value="'+update_previous+'"/>');
364
 
365
- $.ajax({
366
- type: 'POST',
367
- url: 'admin.php?page=pmxi-admin-import&action=options',
368
- data: $("form").serialize(),
369
- success: function(data) {
370
- switch (data.status)
371
- {
372
- case 'process':
373
- $('.wrap').append(data.log);
374
- $(window).scrollTop($(document).height());
375
- process(false, data.update_previous);
376
- break;
377
- case 'stop':
378
- $('form.options').remove();
379
- var import_stats = '';
380
- import_stats = '<p><b> Import started at</b> ' + data.start_time + '</p>';
381
- import_stats += '<p><b> Import ended at</b> ' + data.end_time + '</p>';
382
- import_stats += '<p><b> Import time</b> ' + data.import_time + '</p>';
383
- $('.wrap').append(data.log + import_stats);
384
- break;
385
- }
386
- },
387
- error: function(request, status, error){
388
- $('form.options').hide();
389
- var error = "<script type='text/javascript'>(function($){$('#status').html('Error');window.onbeforeunload = false;})(jQuery);</script>";
390
- if (request.responseText.indexOf('options') === -1) $('.wrap').append(error + request.responseText); else $('form.options').append(error).submit();
391
- },
392
- dataType: "json"
393
- });
394
- }
395
 
396
- $('.ajax-import').click(function(e){
397
- e.preventDefault();
398
- $('form').hide();
399
- $('#process').show();
400
- $('#status').each(function () {
401
- var $this = $(this);
402
- if ($this.html().match(/\.{3}$/)) {
403
- var dots = 0;
404
- var status = $this.html().replace(/\.{3}$/, '');
405
- var interval ;
406
- interval = setInterval(function () {
407
- if ($this.html().match(new RegExp(status + '\\.{1,3}$', ''))) {
408
- $this.html(status + '...'.substr(0, dots++ % 3 + 1));
409
- } else {
410
- clearInterval(interval);
411
- }
412
- }, 1000);
413
- }
414
  });
415
- window.onbeforeunload = function () {
416
- return 'WARNING:\nImport process in under way, leaving the page will interrupt\nthe operation and most likely to cause leftovers in posts.';
417
- };
418
- process(true, 0);
419
  });
420
 
 
 
 
 
 
 
 
 
 
 
421
  });})(jQuery);
109
  // choose file form: option selection dynamic
110
  // options form: highlight options of selected post type
111
  $('form.choose-file input[name="type"]').click(function() {
112
+ var $container = $(this).parents('.file-type-container');
113
  $('.file-type-container').not($container).removeClass('selected').find('.file-type-options').hide();
114
  $container.addClass('selected').find('.file-type-options').show();
115
  }).filter(':checked').click();
171
  'value':''
172
  };
173
 
174
+ function insertxpath(){
175
+ if (dblclickbuf.selected)
176
+ {
177
+ $(this).val($(this).val() + dblclickbuf.value);
178
+ $('.xml-element[title*="/'+dblclickbuf.value.replace('{','').replace('}','')+'"]').removeClass('selected');
179
+ dblclickbuf.value = '';
180
+ dblclickbuf.selected = false;
181
+ }
182
+ }
183
+
184
  // [xml representation dynamic]
185
  $.fn.xml = function (opt) {
186
  if ( ! this.length) return this;
265
  $('.xml-element[title*="/'+$(this).val().replace('{','').replace('}','')+'"]').addClass('selected');
266
  }
267
  });
268
+
 
 
 
 
 
 
 
 
 
269
  $('#title, #content, .widefat, input[name^=custom_name], textarea[name^=custom_value], input[name^=featured_image], input[name^=unique_key]').bind('focus', insertxpath );
270
 
271
  $(document).mousemove(function () {
358
  });
359
  });
360
 
361
+ /* Categories hierarchy */
 
 
 
362
 
363
+ $('.sortable').nestedSortable({
364
+ handle: 'div',
365
+ items: 'li',
366
+ toleranceElement: '> div',
367
+ update: function () {
368
+ $(this).parents('td:first').find('.hierarhy-output').val(window.JSON.stringify($(this).nestedSortable('toArray', {startDepthCount: 0})));
369
+ if ($('.drag-element:first').find('input').val() == '') $(this).parents('td:first').find('.hierarhy-output').val('');
370
+ }
371
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
 
373
+ $('.drag-element').find('input').live('blur', function(){
374
+ $(this).parents('td:first').find('.hierarhy-output').val(window.JSON.stringify($(this).parents('.sortable:first').nestedSortable('toArray', {startDepthCount: 0})));
375
+ if ($('.drag-element:first').find('input').val() == '') $(this).parents('td:first').find('.hierarhy-output').val('');
376
+ });
377
+
378
+ $('.sortable').find('.remove-ico').live('click', function(){
379
+
380
+ var parent_td = $(this).parents('td:first');
381
+
382
+ $(this).parents('li:first').remove();
383
+ parent_td.find('ol.sortable:first').find('li').each(function(i, e){
384
+ $(this).attr({'id':'item_'+ (i+1)});
 
 
 
 
 
 
385
  });
386
+ parent_td.find('.hierarhy-output').val(window.JSON.stringify(parent_td.find('.sortable:first').nestedSortable('toArray', {startDepthCount: 0})));
387
+ if ($('.drag-element:first').find('input').val() == '') parent_td.find('.hierarhy-output').val('');
 
 
388
  });
389
 
390
+ $('.add-new-ico').click(function(){
391
+ var count = $(this).parents('tr:first').find('ol.sortable').find('li').length + 1;
392
+ $(this).parents('tr:first').find('ol.sortable').append('<li id="item_'+count+'"><div class="drag-element"><input type="text" value="" class="widefat"></div><a class="icon-item remove-ico" href="javascript:void(0);"></a></li>');
393
+ $('.widefat').bind('focus', insertxpath );
394
+ });
395
+
396
+ /* END Categories hierarchy */
397
+
398
+
399
+
400
  });})(jQuery);
static/js/jquery/jquery.mjs.nestedSortable.js ADDED
@@ -0,0 +1,426 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * jQuery UI Nested Sortable
3
+ * v 1.3.5 / 21 jun 2012
4
+ * http://mjsarfatti.com/code/nestedSortable
5
+ *
6
+ * Depends on:
7
+ * jquery.ui.sortable.js 1.8+
8
+ *
9
+ * Copyright (c) 2010-2012 Manuele J Sarfatti
10
+ * Licensed under the MIT License
11
+ * http://www.opensource.org/licenses/mit-license.php
12
+ */
13
+
14
+ (function($) {
15
+
16
+ $.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
17
+
18
+ options: {
19
+ tabSize: 20,
20
+ disableNesting: 'mjs-nestedSortable-no-nesting',
21
+ errorClass: 'mjs-nestedSortable-error',
22
+ listType: 'ol',
23
+ maxLevels: 0,
24
+ protectRoot: false,
25
+ rootID: null,
26
+ rtl: false,
27
+ isAllowed: function(item, parent) { return true; }
28
+ },
29
+
30
+ _create: function() {
31
+ this.element.data('sortable', this.element.data('nestedSortable'));
32
+
33
+ if (!this.element.is(this.options.listType))
34
+ throw new Error('nestedSortable: Please check the listType option is set to your actual list type');
35
+
36
+ return $.ui.sortable.prototype._create.apply(this, arguments);
37
+ },
38
+
39
+ destroy: function() {
40
+ this.element
41
+ .removeData("nestedSortable")
42
+ .unbind(".nestedSortable");
43
+ return $.ui.sortable.prototype.destroy.apply(this, arguments);
44
+ },
45
+
46
+ _mouseDrag: function(event) {
47
+
48
+ //Compute the helpers position
49
+ this.position = this._generatePosition(event);
50
+ this.positionAbs = this._convertPositionTo("absolute");
51
+
52
+ if (!this.lastPositionAbs) {
53
+ this.lastPositionAbs = this.positionAbs;
54
+ }
55
+
56
+ //Do scrolling
57
+ if(this.options.scroll) {
58
+ var o = this.options, scrolled = false;
59
+ if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
60
+
61
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
62
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
63
+ else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
64
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
65
+
66
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
67
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
68
+ else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
69
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
70
+
71
+ } else {
72
+
73
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
74
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
75
+ else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
76
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
77
+
78
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
79
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
80
+ else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
81
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
82
+
83
+ }
84
+
85
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
86
+ $.ui.ddmanager.prepareOffsets(this, event);
87
+ }
88
+
89
+ //Regenerate the absolute position used for position checks
90
+ this.positionAbs = this._convertPositionTo("absolute");
91
+
92
+ // Find the top offset before rearrangement,
93
+ var previousTopOffset = this.placeholder.offset().top;
94
+
95
+ //Set the helper position
96
+ if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
97
+ if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
98
+
99
+ //Rearrange
100
+ for (var i = this.items.length - 1; i >= 0; i--) {
101
+
102
+ //Cache variables and intersection, continue if no intersection
103
+ var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
104
+ if (!intersection) continue;
105
+
106
+ if(itemElement != this.currentItem[0] //cannot intersect with itself
107
+ && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
108
+ && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
109
+ && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
110
+ //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
111
+ ) {
112
+
113
+ $(itemElement).mouseenter();
114
+
115
+ this.direction = intersection == 1 ? "down" : "up";
116
+
117
+ if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
118
+ $(itemElement).mouseleave();
119
+ this._rearrange(event, item);
120
+ } else {
121
+ break;
122
+ }
123
+
124
+ // Clear emtpy ul's/ol's
125
+ this._clearEmpty(itemElement);
126
+
127
+ this._trigger("change", event, this._uiHash());
128
+ break;
129
+ }
130
+ }
131
+
132
+ var parentItem = (this.placeholder[0].parentNode.parentNode &&
133
+ $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
134
+ ? $(this.placeholder[0].parentNode.parentNode)
135
+ : null,
136
+ level = this._getLevel(this.placeholder),
137
+ childLevels = this._getChildLevels(this.helper);
138
+
139
+ // To find the previous sibling in the list, keep backtracking until we hit a valid list item.
140
+ var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
141
+ if (previousItem != null) {
142
+ while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0] || previousItem[0] == this.helper[0]) {
143
+ if (previousItem[0].previousSibling) {
144
+ previousItem = $(previousItem[0].previousSibling);
145
+ } else {
146
+ previousItem = null;
147
+ break;
148
+ }
149
+ }
150
+ }
151
+
152
+ // To find the next sibling in the list, keep stepping forward until we hit a valid list item.
153
+ var nextItem = this.placeholder[0].nextSibling ? $(this.placeholder[0].nextSibling) : null;
154
+ if (nextItem != null) {
155
+ while (nextItem[0].nodeName.toLowerCase() != 'li' || nextItem[0] == this.currentItem[0] || nextItem[0] == this.helper[0]) {
156
+ if (nextItem[0].nextSibling) {
157
+ nextItem = $(nextItem[0].nextSibling);
158
+ } else {
159
+ nextItem = null;
160
+ break;
161
+ }
162
+ }
163
+ }
164
+
165
+ var newList = document.createElement(o.listType);
166
+
167
+ this.beyondMaxLevels = 0;
168
+
169
+ // If the item is moved to the left, send it to its parent's level unless there are siblings below it.
170
+ if (parentItem != null && nextItem == null &&
171
+ (o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth()) ||
172
+ !o.rtl && (this.positionAbs.left < parentItem.offset().left))) {
173
+ parentItem.after(this.placeholder[0]);
174
+ this._clearEmpty(parentItem[0]);
175
+ this._trigger("change", event, this._uiHash());
176
+ }
177
+ // If the item is below a sibling and is moved to the right, make it a child of that sibling.
178
+ else if (previousItem != null &&
179
+ (o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize) ||
180
+ !o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))) {
181
+ this._isAllowed(previousItem, level, level+childLevels+1);
182
+ if (!previousItem.children(o.listType).length) {
183
+ previousItem[0].appendChild(newList);
184
+ }
185
+ // If this item is being moved from the top, add it to the top of the list.
186
+ if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
187
+ previousItem.children(o.listType).prepend(this.placeholder);
188
+ }
189
+ // Otherwise, add it to the bottom of the list.
190
+ else {
191
+ previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
192
+ }
193
+ this._trigger("change", event, this._uiHash());
194
+ }
195
+ else {
196
+ this._isAllowed(parentItem, level, level+childLevels);
197
+ }
198
+
199
+ //Post events to containers
200
+ this._contactContainers(event);
201
+
202
+ //Interconnect with droppables
203
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
204
+
205
+ //Call callbacks
206
+ this._trigger('sort', event, this._uiHash());
207
+
208
+ this.lastPositionAbs = this.positionAbs;
209
+ return false;
210
+
211
+ },
212
+
213
+ _mouseStop: function(event, noPropagation) {
214
+
215
+ // If the item is in a position not allowed, send it back
216
+ if (this.beyondMaxLevels) {
217
+
218
+ this.placeholder.removeClass(this.options.errorClass);
219
+
220
+ if (this.domPosition.prev) {
221
+ $(this.domPosition.prev).after(this.placeholder);
222
+ } else {
223
+ $(this.domPosition.parent).prepend(this.placeholder);
224
+ }
225
+
226
+ this._trigger("revert", event, this._uiHash());
227
+
228
+ }
229
+
230
+ // Clean last empty ul/ol
231
+ for (var i = this.items.length - 1; i >= 0; i--) {
232
+ var item = this.items[i].item[0];
233
+ this._clearEmpty(item);
234
+ }
235
+
236
+ $.ui.sortable.prototype._mouseStop.apply(this, arguments);
237
+
238
+ },
239
+
240
+ serialize: function(options) {
241
+
242
+ var o = $.extend({}, this.options, options),
243
+ items = this._getItemsAsjQuery(o && o.connected),
244
+ str = [];
245
+
246
+ $(items).each(function() {
247
+ var res = ($(o.item || this).attr(o.attribute || 'id') || '')
248
+ .match(o.expression || (/(.+)[-=_](.+)/)),
249
+ pid = ($(o.item || this).parent(o.listType)
250
+ .parent(o.items)
251
+ .attr(o.attribute || 'id') || '')
252
+ .match(o.expression || (/(.+)[-=_](.+)/));
253
+
254
+ if (res) {
255
+ str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
256
+ + '='
257
+ + (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
258
+ }
259
+ });
260
+
261
+ if(!str.length && o.key) {
262
+ str.push(o.key + '=');
263
+ }
264
+
265
+ return str.join('&');
266
+
267
+ },
268
+
269
+ toHierarchy: function(options) {
270
+
271
+ var o = $.extend({}, this.options, options),
272
+ sDepth = o.startDepthCount || 0,
273
+ ret = [];
274
+
275
+ $(this.element).children(o.items).each(function () {
276
+ var level = _recursiveItems(this);
277
+ ret.push(level);
278
+ });
279
+
280
+ return ret;
281
+
282
+ function _recursiveItems(item) {
283
+ var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
284
+ if (id) {
285
+ var currentItem = {"id" : id[2]};
286
+ if ($(item).children(o.listType).children(o.items).length > 0) {
287
+ currentItem.children = [];
288
+ $(item).children(o.listType).children(o.items).each(function() {
289
+ var level = _recursiveItems(this);
290
+ currentItem.children.push(level);
291
+ });
292
+ }
293
+ return currentItem;
294
+ }
295
+ }
296
+ },
297
+
298
+ toArray: function(options) {
299
+
300
+ var o = $.extend({}, this.options, options),
301
+ sDepth = o.startDepthCount || 0,
302
+ ret = [],
303
+ left = 2;
304
+
305
+ /*ret.push({
306
+ "item_id": o.rootID,
307
+ "parent_id": 'none',
308
+ "depth": sDepth,
309
+ "left": '1',
310
+ "right": ($(o.items, this.element).length + 1) * 2
311
+ });*/
312
+
313
+ $(this.element).children(o.items).each(function () {
314
+ left = _recursiveArray(this, sDepth + 1, left);
315
+ });
316
+
317
+ ret = ret.sort(function(a,b){ return (a.left - b.left); });
318
+
319
+ return ret;
320
+
321
+ function _recursiveArray(item, depth, left) {
322
+
323
+ var right = left + 1,
324
+ id,
325
+ pid;
326
+
327
+ if ($(item).children(o.listType).children(o.items).length > 0) {
328
+ depth ++;
329
+ $(item).children(o.listType).children(o.items).each(function () {
330
+ right = _recursiveArray($(this), depth, right);
331
+ });
332
+ depth --;
333
+ }
334
+
335
+ id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
336
+
337
+ if (depth === sDepth + 1) {
338
+ pid = o.rootID;
339
+ } else {
340
+ var parentItem = ($(item).parent(o.listType)
341
+ .parent(o.items)
342
+ .attr(o.attribute || 'id'))
343
+ .match(o.expression || (/(.+)[-=_](.+)/));
344
+ pid = parentItem[2];
345
+ }
346
+
347
+ if (id) {
348
+ ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right, "xpath":$(item).find('input').val()});
349
+ }
350
+
351
+ left = right + 1;
352
+ return left;
353
+ }
354
+
355
+ },
356
+
357
+ _clearEmpty: function(item) {
358
+
359
+ var emptyList = $(item).children(this.options.listType);
360
+ if (emptyList.length && !emptyList.children().length) {
361
+ emptyList.remove();
362
+ }
363
+
364
+ },
365
+
366
+ _getLevel: function(item) {
367
+
368
+ var level = 1;
369
+
370
+ if (this.options.listType) {
371
+ var list = item.closest(this.options.listType);
372
+ while (list && list.length > 0 &&
373
+ !list.is('.ui-sortable')) {
374
+ level++;
375
+ list = list.parent().closest(this.options.listType);
376
+ }
377
+ }
378
+
379
+ return level;
380
+ },
381
+
382
+ _getChildLevels: function(parent, depth) {
383
+ var self = this,
384
+ o = this.options,
385
+ result = 0;
386
+ depth = depth || 0;
387
+
388
+ $(parent).children(o.listType).children(o.items).each(function (index, child) {
389
+ result = Math.max(self._getChildLevels(child, depth + 1), result);
390
+ });
391
+
392
+ return depth ? result + 1 : result;
393
+ },
394
+
395
+ _isAllowed: function(parentItem, level, levels) {
396
+ var o = this.options,
397
+ isRoot = $(this.domPosition.parent).hasClass('ui-sortable') ? true : false,
398
+ maxLevels = this.placeholder.closest('.ui-sortable').nestedSortable('option', 'maxLevels'); // this takes into account the maxLevels set to the recipient list
399
+
400
+ // Is the root protected?
401
+ // Are we trying to nest under a no-nest?
402
+ // Are we nesting too deep?
403
+ if (!o.isAllowed(parentItem, this.placeholder) ||
404
+ parentItem && parentItem.hasClass(o.disableNesting) ||
405
+ o.protectRoot && (parentItem == null && !isRoot || isRoot && level > 1)) {
406
+ this.placeholder.addClass(o.errorClass);
407
+ if (maxLevels < levels && maxLevels != 0) {
408
+ this.beyondMaxLevels = levels - maxLevels;
409
+ } else {
410
+ this.beyondMaxLevels = 1;
411
+ }
412
+ } else {
413
+ if (maxLevels < levels && maxLevels != 0) {
414
+ this.placeholder.addClass(o.errorClass);
415
+ this.beyondMaxLevels = levels - maxLevels;
416
+ } else {
417
+ this.placeholder.removeClass(o.errorClass);
418
+ this.beyondMaxLevels = 0;
419
+ }
420
+ }
421
+ }
422
+
423
+ }));
424
+
425
+ $.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
426
+ })(jQuery);
views/admin/import/index.php CHANGED
@@ -39,6 +39,7 @@
39
  <div class="file-type-options">
40
  <input type="text" class="regular-text" name="ftp[url]" value="<?php echo esc_attr($post['ftp']['url']) ?>" /><br />
41
  <input type="text" name="ftp[user]" title="username" /><strong>:</strong><input type="password" name="ftp[pass]" title="passowrd" />
 
42
  </div>
43
  </div>
44
  <div class="file-type-container">
@@ -96,7 +97,7 @@
96
  </p>
97
  </div>
98
  <br />
99
- <table><tr><td class="note"><b>*</b>&nbsp;</td><td class="note"><?php _e('These options support shell wildcard patterns<a href="#help" class="help" title="A shell wildcard pattern is a string used by *nix systems for referencing several files at once. The most common case is using asterisk symbol in the place of any set of characters, e.g. `*.xml` would correspond to any file with `xml` extension.">?</a> which enables linking several XML files to the same import. The option is useful when the exact source path is not known upfront or is going to change, e.g. some content providers submit XML files each time with a new name.<p> CSV files are converted to XML using YQL. YQL is a service hosted by Yahoo. For this to work, WP All Import must be installed on a public-facing server (not localhost) and the /wp-content/uploads/wpallimport/ folder must be accessible to Yahoo over HTTP.</p>', 'pmxi_plugin') ?></td></tr></table>
100
  </form>
101
  </td>
102
  <td class="right">
39
  <div class="file-type-options">
40
  <input type="text" class="regular-text" name="ftp[url]" value="<?php echo esc_attr($post['ftp']['url']) ?>" /><br />
41
  <input type="text" name="ftp[user]" title="username" /><strong>:</strong><input type="password" name="ftp[pass]" title="passowrd" />
42
+ <div class="note"><b>*</b>&nbsp;<?php _e('These options support shell wildcard patterns<a href="#help" class="help" title="A shell wildcard pattern is a string used by *nix systems for referencing several files at once. The most common case is using asterisk symbol in the place of any set of characters, e.g. `*.xml` would correspond to any file with `xml` extension.">?</a> which enables linking several XML files to the same import. The option is useful when the exact source path is not known upfront or is going to change, e.g. some content providers submit XML files each time with a new name.', 'pmxi_plugin') ?></div>
43
  </div>
44
  </div>
45
  <div class="file-type-container">
97
  </p>
98
  </div>
99
  <br />
100
+ <table><tr><td class="note"></td></tr></table>
101
  </form>
102
  </td>
103
  <td class="right">
views/admin/import/options.php CHANGED
@@ -1,3 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <form class="options <?php echo ! $this->isWizard ? 'edit' : '' ?>" method="post">
2
  <table class="layout">
3
  <tr>
@@ -30,13 +56,37 @@
30
  <label for="type_post"><?php _e('Create Posts', 'pmxi_plugin') ?></label>
31
  </h3>
32
  <div class="post-type-options">
33
- <table class="form-table">
34
- <tr>
35
- <th><?php _e('Categories', 'pmxi_plugin') ?> <a href="#help" class="help" title="<?php _e('Enter Category IDs or Names separated by commas. Enclose a name with double quotes if it contains comma.', 'pmxi_plugin') ?>">?</a></th>
36
- <td><input type="text" class="widefat" name="categories" value="<?php echo esc_attr($post['categories']) ?>" /></td>
37
- <td class="delim">
38
- <input type="text" class="small" name="categories_delim" maxlength="1" value="<?php echo esc_attr($post['categories_delim']) ?>" />
39
- <a href="#help" class="help" title="<?php _e('Delimiter used for category list', 'pmxi_plugin') ?>">?</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  </td>
41
  </tr>
42
  <tr>
@@ -53,14 +103,36 @@
53
  <?php $post_taxonomies = array_diff_key(get_taxonomies_by_object_type(array('post'), 'object'), array_flip(array('category', 'post_tag', 'post_format'))) ?>
54
  <?php foreach ($post_taxonomies as $ctx): ?>
55
  <tr class="post_taxonomy" data-type="<?php echo implode(' ', $ctx->object_type) ?>">
56
- <th><nobr><?php echo $ctx->labels->name ?> <a href="#help" class="help" title="<?php _e('Enter taxonomies separated by commas.', 'pmxi_plugin') ?>">?</a></nobr></th>
57
- <td><input type="text" name="post_taxonomies[<?php echo $ctx->name ?>]" class="widefat" value="<?php echo esc_attr(isset($post['post_taxonomies'][$ctx->name]) ? $post['post_taxonomies'][$ctx->name] : '') ?>" /></td>
58
- <td class="delim">
59
- <input type="text" class="small" name="post_taxonomies_delim[<?php echo $ctx->name ?>]" maxlength="1" value="<?php echo esc_attr(isset($post['post_taxonomies_delim'][$ctx->name]) ? $post['post_taxonomies_delim'][$ctx->name] : ',') ?>" />
60
- <a href="#help" class="help" title="<?php _e('Delimiter used for taxonomy list', 'pmxi_plugin') ?>">?</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  </td>
62
  </tr>
63
- <?php endforeach ?>
64
  </table>
65
  </div>
66
  </div>
@@ -93,11 +165,32 @@
93
  <?php $page_taxonomies = get_taxonomies_by_object_type('page', 'object') ?>
94
  <?php foreach ($page_taxonomies as $ctx): ?>
95
  <tr class="page_taxonomy" data-type="<?php echo implode(' ', $ctx->object_type) ?>">
96
- <th><nobr><?php echo $ctx->labels->name ?> <a href="#help" class="help" title="<?php _e('Enter taxonomies separated by commas.', 'pmxi_plugin') ?>">?</a></nobr></th>
97
- <td><input type="text" name="page_taxonomies[<?php echo $ctx->name ?>]" class="widefat" value="<?php echo esc_attr(isset($post['page_taxonomies'][$ctx->name]) ? $post['page_taxonomies'][$ctx->name] : '') ?>" /></td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  <td class="delim">
99
- <input type="text" class="small" name="page_taxonomies_delim[<?php echo $ctx->name ?>]" maxlength="1" value="<?php echo esc_attr(isset($post['page_taxonomies_delim'][$ctx->name]) ? $post['page_taxonomies_delim'][$ctx->name] : ',') ?>" />
100
- <a href="#help" class="help" title="<?php _e('Delimiter used for taxonomy list', 'pmxi_plugin') ?>">?</a>
101
  </td>
102
  </tr>
103
  <?php endforeach ?>
@@ -250,6 +343,12 @@
250
  <label for="is_keep_status"><?php _e('Keep status', 'pmxi_plugin') ?></label>
251
  <a href="#help" class="help" title="<?php _e('Check this option if you do not want previously imported posts to change their publish status or being restored from Trash.', 'pmxi_plugin') ?>">?</a>
252
  </div>
 
 
 
 
 
 
253
  <div>
254
  <input type="hidden" name="is_keep_categories" value="0" />
255
  <input type="checkbox" id="is_keep_categories" name="is_keep_categories" value="1" <?php echo $post['is_keep_categories'] ? 'checked="checked"': '' ?> />
@@ -294,9 +393,6 @@
294
  </tr>
295
  </table>
296
  </form>
297
- <div id="process" style="display:none;">
298
- <?php include PMXI_Plugin::ROOT_DIR . '/views/admin/import/process.php'; ?>
299
- </div>
300
  <script type="text/javascript">
301
  (function($){$(function(){
302
  $('select[name="custom_type"]').change(function () {
1
+ <?php
2
+ if (!function_exists('reverse_taxonomies_html')) {
3
+ function reverse_taxonomies_html($post_taxonomies, $item_id, $i){
4
+ $childs = array();
5
+ foreach ($post_taxonomies as $j => $cat) if ($cat->parent_id == $item_id) { $childs[] = $cat; }
6
+
7
+ if (!empty($childs)){
8
+ ?>
9
+ <ol>
10
+ <?php
11
+ foreach ($childs as $child_cat){
12
+ $i++;
13
+ ?>
14
+ <li id="item_<?php echo $i; ?>">
15
+ <div class="drag-element"><input class="widefat" type="text" value="<?php echo $child_cat->xpath; ?>"/></div><a href="javascript:void(0);" class="icon-item remove-ico"></a>
16
+ <?php echo reverse_taxonomies_html($post_taxonomies, $child_cat->item_id, $i); ?>
17
+ </li>
18
+ <?php
19
+ }
20
+ ?>
21
+ </ol>
22
+ <?php
23
+ }
24
+ }
25
+ }
26
+ ?>
27
  <form class="options <?php echo ! $this->isWizard ? 'edit' : '' ?>" method="post">
28
  <table class="layout">
29
  <tr>
56
  <label for="type_post"><?php _e('Create Posts', 'pmxi_plugin') ?></label>
57
  </h3>
58
  <div class="post-type-options">
59
+ <table class="form-table">
60
+ <tr>
61
+ <th><?php _e('Categories', 'pmxi_plugin') ?> <a href="#help" class="help" title="<?php _e('Enter Category IDs or Names.', 'pmxi_plugin') ?>">?</a></th>
62
+ <td>
63
+ <ol class="sortable no-margin">
64
+ <?php if (!empty($post['categories'])):?>
65
+ <?php
66
+ $categories = json_decode($post['categories']);
67
+ if (!empty($categories) and is_array($categories)): foreach ($categories as $i => $cat) {
68
+ if (is_null($cat->parent_id) or empty($cat->parent_id))
69
+ {
70
+ ?>
71
+ <li id="item_<?php echo ($i+1); ?>">
72
+ <div class="drag-element"><input type="text" class="widefat" value="<?php echo $cat->xpath; ?>"/></div>
73
+ <?php echo reverse_taxonomies_html($categories, $cat->item_id, ($i+1)); ?>
74
+ </li>
75
+ <?php
76
+ }
77
+ }; else: ?>
78
+ <li id="item_1"><div class="drag-element"><input type="text" class="widefat" value=""/></div></li>
79
+ <?php endif;?>
80
+ <?php else: ?>
81
+ <li id="item_1"><div class="drag-element"><input type="text" class="widefat" value=""/></div></li>
82
+ <?php endif; ?>
83
+ </ol>
84
+ <input type="hidden" class="hierarhy-output" name="categories" value="<?php echo esc_attr($post['categories']) ?>"/>
85
+ <div class="hidden" id="dialog-confirm-category-removing" title="Delete categories?">Remove only current category or current category with subcategories?</div>
86
+ </td>
87
+ <td class="delim">
88
+ <a href="javascript:void(0);" class="icon-item add-new-ico"></a>
89
+ <a href="#help" class="help" title="<?php _e('Drag&Drop inputs to create categories hierarchy', 'pmxi_plugin') ?>">?</a>
90
  </td>
91
  </tr>
92
  <tr>
103
  <?php $post_taxonomies = array_diff_key(get_taxonomies_by_object_type(array('post'), 'object'), array_flip(array('category', 'post_tag', 'post_format'))) ?>
104
  <?php foreach ($post_taxonomies as $ctx): ?>
105
  <tr class="post_taxonomy" data-type="<?php echo implode(' ', $ctx->object_type) ?>">
106
+ <th><nobr><?php echo $ctx->labels->name ?> <a href="#help" class="help" title="<?php _e('Enter taxonomy <b>'.$ctx->labels->name.'</b> terms IDs or Names.', 'pmxi_plugin') ?>">?</a></nobr></th>
107
+ <td>
108
+ <ol class="sortable no-margin">
109
+ <?php if (!empty($post['post_taxonomies'][$ctx->name])):
110
+ $taxonomies_hierarchy = json_decode($post['post_taxonomies'][$ctx->name]);
111
+ if (!empty($taxonomies_hierarchy) and is_array($taxonomies_hierarchy)): foreach ($taxonomies_hierarchy as $i => $cat) {
112
+ if (is_null($cat->parent_id) or empty($cat->parent_id))
113
+ {
114
+ ?>
115
+ <li id="item_<?php echo ($i+1); ?>">
116
+ <div class="drag-element"><input type="text" class="widefat" value="<?php echo $cat->xpath; ?>"/></div>
117
+ <?php echo reverse_taxonomies_html($taxonomies_hierarchy, $cat->item_id, ($i+1)); ?>
118
+ </li>
119
+ <?php
120
+ }
121
+ }; else:?>
122
+ <li id="item_1"><div class="drag-element"><input type="text" class="widefat" value=""/></div></li>
123
+ <?php endif;
124
+ else: ?>
125
+ <li id="item_1"><div class="drag-element"><input type="text" class="widefat" value=""/></div></li>
126
+ <?php endif; ?>
127
+ </ol>
128
+ <input type="hidden" class="hierarhy-output" name="post_taxonomies[<?php echo $ctx->name ?>]" value="<?php echo esc_attr($post['post_taxonomies'][$ctx->name]) ?>"/>
129
+ </td>
130
+ <td class="delim">
131
+ <a href="javascript:void(0);" class="icon-item add-new-ico"></a>
132
+ <a href="#help" class="help" title="<?php _e('Drag&Drop inputs to create taxonomies hierarchy', 'pmxi_plugin') ?>">?</a>
133
  </td>
134
  </tr>
135
+ <?php endforeach; ?>
136
  </table>
137
  </div>
138
  </div>
165
  <?php $page_taxonomies = get_taxonomies_by_object_type('page', 'object') ?>
166
  <?php foreach ($page_taxonomies as $ctx): ?>
167
  <tr class="page_taxonomy" data-type="<?php echo implode(' ', $ctx->object_type) ?>">
168
+ <th><nobr><?php echo $ctx->labels->name ?> <a href="#help" class="help" title="<?php _e('Enter taxonomy <b>'.$ctx->labels->name.'</b> terms IDs or Names.', 'pmxi_plugin') ?>">?</a></nobr></th>
169
+ <td>
170
+ <ol class="sortable no-margin">
171
+ <?php if (!empty($post['page_taxonomies'][$ctx->name])):
172
+ $taxonomies_hierarchy = json_decode($post['page_taxonomies'][$ctx->name]);
173
+ foreach ($taxonomies_hierarchy as $i => $cat) {
174
+ if (is_null($cat->parent_id) or empty($cat->parent_id))
175
+ {
176
+ ?>
177
+ <li id="item_<?php echo ($i+1); ?>">
178
+ <div class="drag-element"><input type="text" class="widefat" value="<?php echo $cat->xpath; ?>"/></div>
179
+ <?php echo reverse_taxonomies_html($taxonomies_hierarchy, $cat->item_id, ($i+1)); ?>
180
+ </li>
181
+ <?php
182
+ }
183
+ }
184
+ else: ?>
185
+ <li id="item_1"><div class="drag-element"><input type="text" class="widefat" value=""/></div></li>
186
+ <?php endif; ?>
187
+ </ol>
188
+ <input type="hidden" class="hierarhy-output" name="page_taxonomies[<?php echo $ctx->name ?>]" value="<?php echo esc_attr($post['page_taxonomies'][$ctx->name]) ?>"/>
189
+ <!--input type="text" name="page_taxonomies[<?php echo $ctx->name ?>]" class="widefat" value="<?php echo esc_attr(isset($post['page_taxonomies'][$ctx->name]) ? $post['page_taxonomies'][$ctx->name] : '') ?>" /-->
190
+ </td>
191
  <td class="delim">
192
+ <a href="javascript:void(0);" class="icon-item add-new-ico"></a>
193
+ <a href="#help" class="help" title="<?php _e('Drag&Drop inputs to create taxonomies hierarchy', 'pmxi_plugin') ?>">?</a>
194
  </td>
195
  </tr>
196
  <?php endforeach ?>
343
  <label for="is_keep_status"><?php _e('Keep status', 'pmxi_plugin') ?></label>
344
  <a href="#help" class="help" title="<?php _e('Check this option if you do not want previously imported posts to change their publish status or being restored from Trash.', 'pmxi_plugin') ?>">?</a>
345
  </div>
346
+ <div>
347
+ <input type="hidden" name="is_keep_content" value="0" />
348
+ <input type="checkbox" id="is_keep_content" name="is_keep_content" value="1" <?php echo $post['is_keep_content'] ? 'checked="checked"': '' ?> />
349
+ <label for="is_keep_content"><?php _e('Keep content', 'pmxi_plugin') ?></label>
350
+ <a href="#help" class="help" title="<?php _e('Re-run an importer to pull in one more custom field... without nuking their edits in the process..', 'pmxi_plugin') ?>">?</a>
351
+ </div>
352
  <div>
353
  <input type="hidden" name="is_keep_categories" value="0" />
354
  <input type="checkbox" id="is_keep_categories" name="is_keep_categories" value="1" <?php echo $post['is_keep_categories'] ? 'checked="checked"': '' ?> />
393
  </tr>
394
  </table>
395
  </form>
 
 
 
396
  <script type="text/javascript">
397
  (function($){$(function(){
398
  $('select[name="custom_type"]').change(function () {
views/admin/import/process.php CHANGED
@@ -3,4 +3,29 @@
3
  <hr />
4
 
5
  <p><?php _e('Importing may take some time. Please do not close browser or refresh the page untill process is complete.', 'pmxi_plugin') ?></p>
6
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <hr />
4
 
5
  <p><?php _e('Importing may take some time. Please do not close browser or refresh the page untill process is complete.', 'pmxi_plugin') ?></p>
6
+ </div>
7
+
8
+ <script type="text/javascript">
9
+ //<![CDATA[
10
+ (function($){
11
+ $('#status').each(function () {
12
+ var $this = $(this);
13
+ if ($this.html().match(/\.{3}$/)) {
14
+ var dots = 0;
15
+ var status = $this.html().replace(/\.{3}$/, '');
16
+ var interval ;
17
+ interval = setInterval(function () {
18
+ if ($this.html().match(new RegExp(status + '\\.{1,3}$', ''))) {
19
+ $this.html(status + '...'.substr(0, dots++ % 3 + 1));
20
+ } else {
21
+ clearInterval(interval);
22
+ }
23
+ }, 1000);
24
+ }
25
+ });
26
+ window.onbeforeunload = function () {
27
+ return 'WARNING:\nImport process in under way, leaving the page will interrupt\nthe operation and most likely to cause leftovers in posts.';
28
+ };
29
+ })(jQuery);
30
+ //]]>
31
+ </script>
views/admin/import/tag.php CHANGED
@@ -8,5 +8,5 @@
8
  </div>
9
  </div>
10
  <div class="clear"></div>
11
- <div class="xml resetable"><?php if (!empty($elements)) { $this->shrink_xml_element($elements->item($tagno - 1), true); $this->render_xml_element($elements->item($tagno - 1), true); } ?></div>
12
  </div>
8
  </div>
9
  </div>
10
  <div class="clear"></div>
11
+ <div class="xml resetable"> <?php if (!empty($elements)) $this->render_xml_element($elements->item($tagno - 1), true); ?></div>
12
  </div>
views/admin/manage/update.php CHANGED
@@ -16,9 +16,6 @@
16
  </p>
17
 
18
  </form>
19
- <div id="process" style="display:none;">
20
- <?php include PMXI_Plugin::ROOT_DIR . '/views/admin/import/process.php'; ?>
21
- </div>
22
  <?php else: ?>
23
  <div class="error">
24
  <p><?php _e('Update feature is not available for this import since it has no external path linked.') ?></p>
16
  </p>
17
 
18
  </form>
 
 
 
19
  <?php else: ?>
20
  <div class="error">
21
  <p><?php _e('Update feature is not available for this import since it has no external path linked.') ?></p>
views/admin/settings/index.php CHANGED
@@ -40,6 +40,7 @@
40
  <h3><?php _e('XML parsing filters', 'pmxi_plugin') ?></h3>
41
 
42
  <div><?php printf(__('Filter XML contains HTML entities %s', 'pmxi_plugin'), '<input type="radio" name="html_entities" value="1" '.((!empty($post['html_entities'])) ? 'checked="checked"' : '').' /> Yes <input type="radio" name="html_entities" value="0" '.((empty($post['html_entities'])) ? 'checked="checked"' : '').' /> No') ?></div>
 
43
  <p class="submit-buttons">
44
  <?php wp_nonce_field('edit-settings', '_wpnonce_edit-settings') ?>
45
  <input type="hidden" name="is_settings_submitted" value="1" />
40
  <h3><?php _e('XML parsing filters', 'pmxi_plugin') ?></h3>
41
 
42
  <div><?php printf(__('Filter XML contains HTML entities %s', 'pmxi_plugin'), '<input type="radio" name="html_entities" value="1" '.((!empty($post['html_entities'])) ? 'checked="checked"' : '').' /> Yes <input type="radio" name="html_entities" value="0" '.((empty($post['html_entities'])) ? 'checked="checked"' : '').' /> No') ?></div>
43
+ <div><?php printf(__('UTF-8 decode %s', 'pmxi_plugin'), '<input type="radio" name="utf8_decode" value="1" '.((!empty($post['utf8_decode'])) ? 'checked="checked"' : '').' /> Yes <input type="radio" name="utf8_decode" value="0" '.((empty($post['utf8_decode'])) ? 'checked="checked"' : '').' /> No') ?></div>
44
  <p class="submit-buttons">
45
  <?php wp_nonce_field('edit-settings', '_wpnonce_edit-settings') ?>
46
  <input type="hidden" name="is_settings_submitted" value="1" />