PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.15.0
Import WP – CSV & XML Import Export for WordPress v2.15.0
2.15.1 2.15.0 2.14.24 2.14.23 2.7.0 2.7.1 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 2.9.1 All 144 releases
← All changes | class/Common/Importer/ImporterManager.php +362 -42 2.7.7 → 2.15.0 View file →
@@ -4,16 +4,22 @@
4 4
5 5 use ImportWP\Common\Filesystem\Filesystem;
6 6 use ImportWP\Common\Importer\Config\Config;
7 7 use ImportWP\Common\Importer\File\CSVFile;
8 +use ImportWP\Common\Importer\File\JSONFile;
8 9 use ImportWP\Common\Importer\File\XMLFile;
10 +use ImportWP\Common\Importer\Mapper\AttachmentMapper;
11 +use ImportWP\Common\Importer\Mapper\CommentMapper;
9 12 use ImportWP\Common\Importer\Mapper\PostMapper;
10 13 use ImportWP\Common\Importer\Mapper\TermMapper;
11 14 use ImportWP\Common\Importer\Mapper\UserMapper;
12 15 use ImportWP\Common\Importer\Parser\CSVParser;
16 +use ImportWP\Common\Importer\Parser\JSONParser;
13 17 use ImportWP\Common\Importer\Parser\XMLParser;
14 18 use ImportWP\Common\Importer\Permission\Permission;
15 19 use ImportWP\Common\Importer\State\ImporterState;
20 +use ImportWP\Common\Importer\Template\AttachmentTemplate;
21 +use ImportWP\Common\Importer\Template\CommentTemplate;
16 22 use ImportWP\Common\Importer\Template\CustomPostTypeTemplate;
17 23 use ImportWP\Common\Importer\Template\PageTemplate;
18 24 use ImportWP\Common\Importer\Template\PostTemplate;
19 25 use ImportWP\Common\Importer\Template\Template;
@@ -21,8 +27,9 @@
21 27 use ImportWP\Common\Importer\Template\TermTemplate;
22 28 use ImportWP\Common\Importer\Template\UserTemplate;
23 29 use ImportWP\Common\Model\ImporterModel;
24 30 use ImportWP\Common\Properties\Properties;
31 +use ImportWP\Common\Runner\ImporterRunnerState;
25 32 use ImportWP\Common\Util\Logger;
26 33 use ImportWP\Common\Util\Util;
27 34 use ImportWP\Container;
28 35 use ImportWP\EventHandler;
@@ -49,11 +56,57 @@
49 56 {
50 57 $this->filesystem = $filesystem;
51 58 $this->template_manager = $template_manager;
52 59 $this->event_handler = $event_handler;
60 +
61 + add_action('admin_init', [$this, 'download_debug_log']);
53 62 }
54 63
55 64 /**
65 + * Stream an importer debug log through an authenticated admin request.
66 + *
67 + * Direct public URLs under uploads/importwp are blocked by .htaccess (CVE-2025-12894).
68 + *
69 + * @return void
70 + */
71 + public function download_debug_log()
72 + {
73 + if (!isset($_GET['page'], $_GET['import'], $_GET['download_debug']) || $_GET['page'] !== 'importwp') {
74 + return;
75 + }
76 +
77 + if (!is_user_logged_in() || !current_user_can('manage_options')) {
78 + wp_die(esc_html__('You do not have permission to download this file.', 'jc-importer'), '', array('response' => 403));
79 + }
80 +
81 + if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_key(wp_unslash($_GET['_wpnonce'])), 'iwp_debug_log_download')) {
82 + wp_die(esc_html__('Invalid download request.', 'jc-importer'), '', array('response' => 403));
83 + }
84 +
85 + $importer_id = intval($_GET['import']);
86 + $importer_data = $this->get_importer($importer_id);
87 + if (!$importer_data) {
88 + wp_die(esc_html__('Invalid download request.', 'jc-importer'), '', array('response' => 403));
89 + }
90 +
91 + if (!$this->is_debug()) {
92 + wp_die(esc_html__('Debug mode is not enabled.', 'jc-importer'), '', array('response' => 403));
93 + }
94 +
95 + $file_path = Logger::getLogFile($importer_id);
96 + if (!is_string($file_path) || !file_exists($file_path)) {
97 + wp_die(esc_html__('Debug log file not found.', 'jc-importer'), '', array('response' => 404));
98 + }
99 +
100 + nocache_headers();
101 + header('Content-Type: text/plain; charset=utf-8');
102 + header('Content-Disposition: attachment; filename="' . basename($file_path) . '"');
103 + header('Content-Length: ' . (string) filesize($file_path));
104 + readfile($file_path);
105 + exit;
106 + }
107 +
108 + /**
56 109 * Get Importers
57 110 *
58 111 * @return ImporterModel[]
59 112 */
@@ -141,8 +194,10 @@
141 194 if ('xml' === $parser) {
142 195 return $this->get_xml_file($importer, $config);
143 196 } elseif ('csv' === $parser) {
144 197 return $this->get_csv_file($importer, $config);
198 + } elseif ('json' === $parser) {
199 + return $this->get_json_file($importer, $config);
145 200 }
146 201
147 202 return false;
148 203 }
@@ -152,8 +207,9 @@
152 207 $importer = $this->get_importer($id);
153 208 $file = new CSVFile($importer->getFile(), $config);
154 209 $file->setDelimiter($importer->getFileSetting('delimiter'));
155 210 $file->setEnclosure($importer->getFileSetting('enclosure'));
211 + $file->setEscape($importer->getFileSetting('escape', "\\"));
156 212 return $file;
157 213 }
158 214
159 215 public function get_xml_file($id, $config)
@@ -163,8 +219,16 @@
163 219 $file->setRecordPath($importer->getFileSetting('base_path'));
164 220 return $file;
165 221 }
166 222
223 + public function get_json_file($id, $config)
224 + {
225 + $importer = $this->get_importer($id);
226 + $file = new JSONFile($importer->getFile(), $config);
227 + $file->setRecordPath($importer->getFileSetting('base_path'));
228 + return $file;
229 + }
230 +
167 231 public function preview_csv_file($id, $fields = [], $row = 0)
168 232 {
169 233 $importer = $this->get_importer($id);
170 234 $config = $this->get_config($importer, true);
@@ -188,8 +252,20 @@
188 252 $record = $parser->getRecord($row);
189 253 return $record->queryGroup(['fields' => $fields]);
190 254 }
191 255
256 + public function preview_json_file($id, $fields = [], $row = 0)
257 + {
258 + $importer = $this->get_importer($id);
259 + $config = $this->get_config($importer, true);
260 +
261 + $file = $this->get_json_file($importer, $config);
262 + $parser = new JSONParser($file);
263 +
264 + $record = $parser->getRecord($row);
265 + return $record->queryGroup(['fields' => $fields]);
266 + }
267 +
192 268 public function process_csv_file($id, $delimiter, $enclosure, $tmp = false)
193 269 {
194 270 $importer = $this->get_importer($id);
195 271 $config = $this->get_config($importer->getId(), $tmp);
@@ -198,36 +274,8 @@
198 274 $file->setDelimiter($delimiter);
199 275 $file->setEnclosure($enclosure);
200 276 $file->processing(true);
201 277
202 - if (empty($importer->getMap())) {
203 -
204 - // we are on first file import
205 - $headings = str_getcsv($file->getRecord(0), $file->getDelimiter(), $file->getEnclosure());
206 - $headings = array_map('trim', $headings);
207 -
208 - $template = $this->get_importer_template($id);
209 - $field_map = $template->generate_field_map($headings, $importer);
210 - $field_map = apply_filters('iwp/importer/generate_field_map', $field_map, $headings, $importer);
211 -
212 - $map = $field_map['map'];
213 - foreach ($map as $key => $value) {
214 - $importer->setMap($key, $value);
215 - }
216 -
217 - $enabled = $field_map['enabled'];
218 - foreach ($enabled as $enabled_field) {
219 - $importer->setEnabled($enabled_field);
220 - }
221 -
222 - // Disabled due to testing:
223 - // https://localdev/wp-admin/tools.php?page=importwp&edit=29&step=1
224 - //
225 - // a:9:{s:8:"template";s:19:"woocommerce-product";s:13:"template_type";s:0:"";s:4:"file";a:2:{s:2:"id";i:9;s:8:"settings";a:6:{s:9:"enclosure";s:1:""";s:9:"delimiter";s:1:",";s:13:"show_headings";b:1;s:5:"setup";b:0;s:5:"count";i:2;s:9:"processed";b:1;}}s:10:"datasource";a:2:{s:4:"type";s:5:"local";s:8:"settings";a:2:{s:10:"remote_url";s:0:"";s:9:"local_url";s:48:"/var/www/html/wp-content/uploads/exportwp/30.csv";}}s:6:"parser";s:3:"csv";s:3:"map";a:0:{}s:7:"enabled";a:0:{}s:11:"permissions";a:0:{}s:8:"settings";a:4:{s:9:"post_type";a:2:{i:0;s:7:"product";i:1;s:17:"product_variation";}s:12:"unique_field";a:3:{i:0;s:2:"ID";i:1;s:4:"_sku";i:2;s:9:"post_name";}s:9:"start_row";N;s:7:"max_row";N;}}
226 - //
227 - $importer->save();
228 - }
229 -
230 278 return $file->getRecordCount();
231 279 }
232 280
233 281 public function process_xml_file($id, $tmp = false)
@@ -252,8 +300,19 @@
252 300
253 301 return $results;
254 302 }
255 303
304 + public function process_json_file($id, $tmp = false)
305 + {
306 + $importer = $this->get_importer($id);
307 + $config = $this->get_config($importer->getId(), $tmp);
308 +
309 + $file = new JSONFile($importer->getFile(), $config);
310 + $file->processing(true);
311 +
312 + return $file->get_path_list();
313 + }
314 +
256 315 /**
257 316 * Link import file to importer via post meta
258 317 *
259 318 * @param ImporterModel $id
@@ -269,8 +328,15 @@
269 328 }
270 329
271 330 $index++;
272 331
332 + // Store uploads-relative paths so site moves / open_basedir changes do not break lookups.
333 + $file_path = wp_normalize_path($file_path);
334 + $relative = Filesystem::to_uploads_relative_path($file_path);
335 + if ($relative !== '' && $relative !== $file_path) {
336 + $file_path = $relative;
337 + }
338 +
273 339 update_post_meta($importer->getId(), '_importer_files', $index);
274 340 update_post_meta($importer->getId(), '_importer_file_' . $index, $file_path);
275 341 return $index;
276 342 }
@@ -284,11 +350,50 @@
284 350 $file_index = 1;
285 351 }
286 352 $file_index++;
287 353
288 - return $importer->getId() . '-' . intval($file_index) . '-';
354 + return $importer->getId() . '-' . intval($file_index) . '-' . wp_generate_password(12, false, false) . '-';
289 355 }
290 356
357 + public function set_custom_upload_path($dir)
358 + {
359 + remove_filter('upload_dir', [$this, 'set_custom_upload_path']);
360 +
361 + $path = $this->filesystem->get_temp_directory();
362 + $url = $this->filesystem->get_temp_directory(true);
363 +
364 + add_filter('upload_dir', [$this, 'set_custom_upload_path']);
365 +
366 + $path .= '/uploads';
367 + $url .= '/uploads';
368 +
369 + if (!is_dir($path)) {
370 + wp_mkdir_p($path);
371 + }
372 +
373 + if (!file_exists($path . '/.htaccess')) {
374 + file_put_contents($path . '/.htaccess', "# Apache 2.4+
375 +<IfModule mod_authz_core.c>
376 + Require all denied
377 +</IfModule>
378 +
379 +# Apache 2.2 and older (or when mod_authz_core isn't available)
380 +<IfModule !mod_authz_core.c>
381 + Deny from all
382 +</IfModule>");
383 + }
384 +
385 + if (!file_exists($path . '/index.html')) {
386 + touch($path . '/index.html');
387 + }
388 +
389 + return array(
390 + 'path' => $path,
391 + 'url' => $url,
392 + 'subdir' => '/importwp/uploads',
393 + ) + $dir;
394 + }
395 +
291 396 public function upload_file($id, $file)
292 397 {
293 398 $importer = $this->get_importer($id);
294 399 Logger::setId($importer->getId());
@@ -293,10 +398,22 @@
293 398 $importer = $this->get_importer($id);
294 399 Logger::setId($importer->getId());
295 400
296 401 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
402 +
403 + $prefix = $this->get_importer_file_prefix($importer);
404 +
405 + $prefix_upload = function ($file) use ($prefix) {
406 + $file['name'] = $prefix . $file['name'];
407 + return $file;
408 + };
409 +
410 + add_filter('wp_handle_upload_prefilter', $prefix_upload);
411 +
297 412 $result = $this->filesystem->upload_file($file, $allowed_file_types);
298 413
414 + remove_filter('wp_handle_upload_prefilter', $prefix_upload);
415 +
299 416 if (is_wp_error($result)) {
300 417 return $result;
301 418 }
302 419
@@ -314,10 +431,86 @@
314 431 Logger::setId($importer->getId());
315 432
316 433 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
317 434 $prefix = $this->get_importer_file_prefix($importer);
318 - $result = $this->filesystem->download_file($source, $filetype, $allowed_file_types, null, $prefix);
319 435
436 + try {
437 +
438 + if (preg_match('/^s?ftp?:\/\//', $source) === 1) {
439 +
440 + if (preg_match('/^(?<protocol>s?ftp):\/\/(?:(?<user>[^\:@]+)(?:\:(?<pass>[^@]+))?@)?(?<host>[^\:\/]+)(?:\:(?<port>[0-9]+))?(?:\/(?<path>.*))$/', $source, $matches) !== 1) {
441 +
442 + return new \WP_Error("IM_RM_FTP_PARSE", __("Unable to parse FTP connection string", 'jc-importer'));
443 + }
444 +
445 + $protocol = isset($matches['protocol']) ? $matches['protocol'] : 'ftp';
446 + $user = isset($matches['user']) ? urldecode($matches['user']) : '';
447 + $pass = isset($matches['pass']) ? urldecode($matches['pass']) : '';
448 + $host = isset($matches['host']) ? $matches['host'] : false;
449 + $port = isset($matches['port']) && !empty($matches['port']) ? $matches['port'] : intval(21);
450 + $path = isset($matches['path']) ? $matches['path'] : false;
451 +
452 + if (!$host) {
453 + return new \WP_Error("IM_RM_FTP_HOST", __("Unable to parse ftp host from connection string", 'jc-importer'));
454 + }
455 +
456 + if (!$path) {
457 + return new \WP_Error("IM_RM_FTP_HOST", __("Unable to parse ftp host from connection string", 'jc-importer'));
458 + }
459 +
460 + /**
461 + * @var \ImportWP\Common\Ftp\Ftp $ftp
462 + */
463 + $ftp = Container::getInstance()->get('ftp');
464 +
465 + $path = apply_filters('iwp/importer/remote_file', $path, $importer);
466 + $path = apply_filters(sprintf('iwp/importer=%d/remote_file', $importer->getId()), $path, $importer);
467 +
468 + $filter_connection_args = [
469 + 'user' => $user,
470 + 'pass' => $pass,
471 + 'host' => $host,
472 + 'port' => $port,
473 + 'path' => $path,
474 + ];
475 + $path = apply_filters(sprintf('iwp/importer/remote_file/source=%s', 'ftp'), $path, $importer, $filter_connection_args);
476 + $path = apply_filters(sprintf('iwp/importer=%d/remote_file/source=ftp', $importer->getId(), 'ftp'), $path, $importer, $filter_connection_args);
477 +
478 + if ($protocol == 'sftp') {
479 +
480 + // require sftp package
481 + require_once __DIR__ . '/../../../libs/autoload.php';
482 +
483 + $sftp = new \phpseclib3\Net\SFTP($host, $port);
484 + if (!$sftp->login($user, $pass)) {
485 + return new \WP_Error('IWP_FTP_0', __("Unable to login to ftp server", 'jc-importer'));
486 + }
487 +
488 + $wp_upload_dir = wp_upload_dir();
489 +
490 + $dest = wp_unique_filename($wp_upload_dir['path'], basename($path));
491 + $wp_dest = $wp_upload_dir['path'] . '/' . $dest;
492 +
493 + if (!$sftp->get($path, $wp_dest)) {
494 + return new \WP_Error('IWP_FTP_2', sprintf(__('Unable to download: %s file via sftp.', 'jc-importer'), $path));
495 + }
496 +
497 + $result = array(
498 + 'dest' => $wp_dest,
499 + 'type' => $this->filesystem->get_filetype($wp_dest),
500 + 'mime' => $this->filesystem->get_file_mime($wp_dest)
501 + );
502 + } else {
503 + $result = $ftp->download_file($path, $host, $user, $pass, false, $port);
504 + }
505 + } else {
506 +
507 + $result = $this->filesystem->download_file($source, $filetype, $allowed_file_types, null, $prefix);
508 + }
509 + } catch (\Exception $e) {
510 + return new \WP_Error($e->getCode(), $e->getMessage());
511 + }
512 +
320 513 if (is_wp_error($result)) {
321 514 return $result;
322 515 }
323 516
@@ -328,16 +521,34 @@
328 521
329 522 return $attachment_id;
330 523 }
331 524
332 - public function local_file($id, $source)
525 + public function local_file($id, $source, $filetype = null)
333 526 {
334 527 $importer = $this->get_importer($id);
335 528 Logger::setId($importer->getId());
336 529
530 + $allowed_bases = apply_filters('iwp/importer/local_file/allowed_directories', [
531 + realpath(WP_CONTENT_DIR) . DIRECTORY_SEPARATOR
532 + ]);
533 +
534 + $source = realpath($source);
535 +
536 + $is_allowed = false;
537 + foreach ($allowed_bases as $allowed_base) {
538 + if ($allowed_base && strpos($source, $allowed_base) === 0) {
539 + $is_allowed = true;
540 + break;
541 + }
542 + }
543 +
544 + if (!$source || !$is_allowed) {
545 + return new \WP_Error('IWP_LOCAL_FILE_1', __('Access to this file path is not allowed.', 'jc-importer'));
546 + }
547 +
337 548 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
338 549 $prefix = $this->get_importer_file_prefix($importer);
339 - $result = $this->filesystem->copy_file($source, $allowed_file_types, null, $prefix);
550 + $result = $this->filesystem->copy_file($source, $allowed_file_types, null, $prefix, $filetype);
340 551
341 552 if (is_wp_error($result)) {
342 553 return $result;
343 554 }
@@ -371,9 +582,9 @@
371 582 $file_path = apply_filters('iwp/importer/file_uploaded/file_path', $file_path, $importer_model);
372 583
373 584 $file_id = $this->link_importer_file($id, $file_path);
374 585 if (!$file_id) {
375 - return new \WP_Error('IWP_IM_01', 'Unable to link importer file');
586 + return new \WP_Error('IWP_IM_01', __('Unable to link importer file', 'jc-importer'));
376 587 }
377 588
378 589 if (is_null($importer_model->getParser())) {
379 590 $importer_model->setParser($file_type);
@@ -434,9 +645,9 @@
434 645
435 646 $base .= str_pad($id, 2, STR_PAD_LEFT) . DIRECTORY_SEPARATOR;
436 647 if (!file_exists($base)) {
437 648 if (!is_writable(dirname($base)) || !mkdir($base)) {
438 - throw new \Exception("Unable to create directory: " . $base);
649 + throw new \Exception(sprintf(__("Unable to create directory: %s", 'jc-importer'), $base));
439 650 }
440 651 }
441 652
442 653 for ($i = 0; $i < ceil(strlen($session) / 2); $i++) {
@@ -443,9 +654,9 @@
443 654 $base .= substr($session, $i * 2, 2) . DIRECTORY_SEPARATOR;
444 655 if (!file_exists($base)) {
445 656
446 657 if (!is_writable(dirname($base)) || !mkdir($base)) {
447 - throw new \Exception("Unable to create directory: " . $base);
658 + throw new \Exception(sprintf(__("Unable to create directory: %s", 'jc-importer'), $base));
448 659 }
449 660 }
450 661
451 662 if ($i >= $max_depth - 2) {
@@ -475,10 +686,13 @@
475 686
476 687 $importer_data = $this->get_importer($id);
477 688 $importer_id = $importer_data->getId();
478 689
479 - $config_data = get_site_option('iwp_importer_config_' . $importer_id, []);
690 + // store current importer
691 + iwp()->importer = $importer_data;
480 692
693 + $config_data = get_option('iwp_importer_config_' . $importer_id, []);
694 +
481 695 $this->event_handler->run('importer_manager.import', [$importer_data]);
482 696
483 697 $state = new ImporterState($importer_id, $user);
484 698
@@ -484,11 +698,16 @@
484 698
485 699 try {
486 700
487 701 Logger::debug('IM -init_state');
702 +
703 + // 1. Set State Session, and load its state
488 704 $state->init($session);
489 705
706 + // if this is a new session, clear config files
490 707 if ($state->has_status('init')) {
708 + // rest importer log.
709 + Logger::clear($importer_id);
491 710 Logger::debug('IM -clear_config_files');
492 711 $this->clear_config_files($importer_id, false, true);
493 712 $config_data['features'] = [
494 713 'session_table' => true
@@ -512,8 +731,9 @@
512 731 // mapper
513 732 Logger::debug('IM -get_importer_mapper');
514 733 $mapper = $this->get_importer_mapper($importer_data, $template, $permission);
515 734
735 + // if this is a new session, build config
516 736 if ($state->has_status('init')) {
517 737
518 738 Logger::debug('IM -generate_config');
519 739
@@ -533,8 +753,45 @@
533 753 $version = 0;
534 754 }
535 755 update_post_meta($importer_id, '_iwp_version', $version);
536 756 $config_data['version'] = $version;
757 +
758 + /**
759 + * Fetch new file if setting is checked
760 + * @since 2.7.15
761 + */
762 + $run_fetch_file = $importer_data->getSetting('run_fetch') || false;
763 + $run_fetch_file = apply_filters('iwp/importer/run_fetch_file', $run_fetch_file);
764 + if ($run_fetch_file) {
765 +
766 + add_filter('upload_dir', [$this, 'set_custom_upload_path']);
767 +
768 + $datasource = $importer_data->getDatasource();
769 + switch ($datasource) {
770 + case 'remote':
771 + $raw_source = $importer_data->getDatasourceSetting('remote_url');
772 + $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer_data);
773 + $source = apply_filters('iwp/importer/datasource/remote', $source, $raw_source, $importer_data);
774 + $attachment_id = $this->remote_file($importer_data, $source, $importer_data->getParser());
775 + break;
776 + case 'local':
777 + $raw_source = $importer_data->getDatasourceSetting('local_url');
778 + $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer_data);
779 + $source = apply_filters('iwp/importer/datasource/local', $source, $raw_source, $importer_data);
780 + $attachment_id = $this->local_file($importer_data, $source, $importer_data->getParser());
781 + break;
782 + default:
783 + // TODO: record error
784 + $attachment_id = new \WP_Error('IWP_CRON_1', sprintf(__('Unable to get new file using datasource: %s', 'jc-importer'), $datasource));
785 + break;
786 + }
787 +
788 + remove_filter('upload_dir', [$this, 'set_custom_upload_path']);
789 +
790 + if (is_wp_error($attachment_id)) {
791 + throw new \Exception(sprintf(__('Importer Datasource: %s', 'jc-importer'), $attachment_id->get_error_message()));
792 + }
793 + }
537 794 }
538 795
539 796 $start = 0;
540 797
@@ -551,21 +808,43 @@
551 808 Logger::debug('IM -get_xml_file');
552 809 $file = $this->get_xml_file($importer_data, $config);
553 810 Logger::debug('IM -load_parser');
554 811 $parser = new XMLParser($file);
812 + } elseif ($importer_data->getParser() === 'json') {
813 + Logger::debug('IM -get_json_file');
814 + $file = $this->get_json_file($importer_data, $config);
815 + Logger::debug('IM -load_parser');
816 + $parser = new JSONParser($file);
555 817 } else {
556 818 $parser = apply_filters('iwp/importer/init_parser', false, $importer_data, $config);
557 819 }
558 820
821 + if (!$parser || !is_object($parser) || !method_exists($parser, 'file')) {
822 + $parser_type = $importer_data->getParser();
823 + throw new \Exception(
824 + sprintf(
825 + __('Unable to load importer parser for type: %s', 'jc-importer'),
826 + $parser_type ? $parser_type : __('unknown', 'jc-importer')
827 + )
828 + );
829 + }
830 +
831 + // if this is a new session, set start / end rows to state
559 832 if ($state->has_status('init')) {
560 833
561 834 Logger::debug('IM -get_record_count');
562 835 $end = $parser->file()->getRecordCount();
563 836
837 + // Capture cancelled status from file processor
838 + $raw_state = ImporterState::get_state($importer_data->getId());
839 + if ($raw_state['status'] === 'cancelled') {
840 + return $raw_state;
841 + }
842 +
564 843 $config_data['start'] = $this->get_start($importer_data, $start);
565 844 $config_data['end'] = $this->get_end($importer_data, $config_data['start'], $end);
566 845
567 - update_site_option('iwp_importer_config_' . $importer_id, $config_data);
846 + update_option('iwp_importer_config_' . $importer_id, $config_data);
568 847
569 848 Logger::debug('IM -update_state');
570 849 $state->update(function ($state) use ($config_data) {
571 850
@@ -583,8 +862,13 @@
583 862
584 863 do_action('iwp/importer/init', $importer_data);
585 864 }
586 865
866 +
867 + add_filter('iwp/importer/mapper/hash_check_enabled', function ($enabled) use ($importer_data) {
868 + return $importer_data->getSetting('hash_check');
869 + });
870 +
587 871 Logger::debug('IM -import');
588 872 $importer = new \ImportWP\Common\Importer\Importer($config);
589 873 $importer->parser($parser);
590 874 $importer->mapper($mapper);
@@ -596,9 +880,11 @@
596 880 } catch (\Exception $e) {
597 881
598 882 // TODO: Missing template errors are currently not being logged to history, possibly others?
599 883 Logger::error('import -error=' . $e->getMessage(), $importer_id);
600 - return $state->error($e)->get_raw();
884 + $state->error($e);
885 + Util::write_status_session_to_file($id, $state);
886 + return $state->get_raw();
601 887 }
602 888
603 889 /**
604 890 * @var Properties $properties
@@ -618,8 +904,38 @@
618 904 return $data;
619 905 })->get_raw();
620 906 }
621 907
908 + public function pause_import($importer_id, $paused)
909 + {
910 + // TODO: set flag for paused.
911 + $state = ImporterState::get_state($importer_id);
912 + if ($paused === 'no') {
913 + ImporterState::clear_flag($importer_id);
914 + $state['status'] = 'running';
915 + } else {
916 + ImporterState::set_paused($importer_id);
917 + $state['status'] = 'paused';
918 + }
919 +
920 + // good chance this will be overwritten
921 + ImporterState::set_state($importer_id, $state);
922 +
923 + return $state;
924 + }
925 +
926 + public function stop_import($importer_id)
927 + {
928 + ImporterState::set_cancelled($importer_id);
929 +
930 + // good chance this will be overwritten
931 + $state = ImporterState::get_state($importer_id);
932 + $state['status'] = 'cancelled';
933 + ImporterState::set_state($importer_id, $state);
934 +
935 + return $state;
936 + }
937 +
622 938 public function get_start($importer_data, $start)
623 939 {
624 940 $tmp_start = $importer_data->getStartRow();
625 941 if (!is_null($tmp_start) && "" !== $tmp_start) {
@@ -652,9 +968,9 @@
652 968 $templates = $this->get_templates();
653 969 $template_name = $importer_model->getTemplate();
654 970
655 971 if (!isset($templates[$template_name])) {
656 - $exception_msg = "Unable to locate importer template: " . $template_name;
972 + $exception_msg = sprintf(__("Unable to locate importer template: %s", 'jc-importer'), $template_name);
657 973 Logger::error('import -get_importer_template=' . $exception_msg, $importer_model->getId());
658 974 throw new \Exception($exception_msg);
659 975 }
660 976
@@ -683,9 +999,11 @@
683 999 $mappers = $this->event_handler->run('mappers.register', [[]]); // apply_filters('iwp/mappers/register', []);
684 1000 $mappers = array_merge($mappers, [
685 1001 'post' => PostMapper::class,
686 1002 'user' => UserMapper::class,
687 - 'term' => TermMapper::class
1003 + 'term' => TermMapper::class,
1004 + 'attachment' => AttachmentMapper::class,
1005 + 'comment' => CommentMapper::class,
688 1006 ]);
689 1007 return $mappers;
690 1008 }
691 1009
@@ -692,9 +1010,9 @@
692 1010 public function get_mapper($key)
693 1011 {
694 1012 $mappers = $this->get_mappers();
695 1013 if (!isset($mappers[$key])) {
696 - return new \WP_Error('IWP_IM_1', 'Unable to locate mapper: ' . $key);
1014 + return new \WP_Error('IWP_IM_1', sprintf(__('Unable to locate mapper: %s', 'jc-importer'), $key));
697 1015 }
698 1016
699 1017 return $mappers[$key];
700 1018 }
@@ -706,8 +1024,10 @@
706 1024 'post' => PostTemplate::class,
707 1025 'page' => PageTemplate::class,
708 1026 'user' => UserTemplate::class,
709 1027 'term' => TermTemplate::class,
1028 + 'attachment' => AttachmentTemplate::class,
1029 + 'comment' => CommentTemplate::class,
710 1030 'custom-post-type' => CustomPostTypeTemplate::class,
711 1031 ]);
712 1032 return $templates;
713 1033 }
@@ -715,9 +1035,9 @@
715 1035 public function get_template($key)
716 1036 {
717 1037 $templates = $this->get_templates();
718 1038 if (!isset($templates[$key])) {
719 - return new \WP_Error('IWP_IM_1', 'Unable to locate template: ' . $key);
1039 + return new \WP_Error('IWP_IM_1', sprintf(__('Unable to locate template: %s', 'jc-importer'), $key));
720 1040 }
721 1041
722 1042 return $templates[$key];
723 1043 }