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 +267 -47 2.9.0 → 2.15.0 View file →
@@ -4,8 +4,9 @@
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;
9 10 use ImportWP\Common\Importer\Mapper\AttachmentMapper;
10 11 use ImportWP\Common\Importer\Mapper\CommentMapper;
11 12 use ImportWP\Common\Importer\Mapper\PostMapper;
@@ -11,8 +12,9 @@
11 12 use ImportWP\Common\Importer\Mapper\PostMapper;
12 13 use ImportWP\Common\Importer\Mapper\TermMapper;
13 14 use ImportWP\Common\Importer\Mapper\UserMapper;
14 15 use ImportWP\Common\Importer\Parser\CSVParser;
16 +use ImportWP\Common\Importer\Parser\JSONParser;
15 17 use ImportWP\Common\Importer\Parser\XMLParser;
16 18 use ImportWP\Common\Importer\Permission\Permission;
17 19 use ImportWP\Common\Importer\State\ImporterState;
18 20 use ImportWP\Common\Importer\Template\AttachmentTemplate;
@@ -54,11 +56,57 @@
54 56 {
55 57 $this->filesystem = $filesystem;
56 58 $this->template_manager = $template_manager;
57 59 $this->event_handler = $event_handler;
60 +
61 + add_action('admin_init', [$this, 'download_debug_log']);
58 62 }
59 63
60 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 + /**
61 109 * Get Importers
62 110 *
63 111 * @return ImporterModel[]
64 112 */
@@ -146,8 +194,10 @@
146 194 if ('xml' === $parser) {
147 195 return $this->get_xml_file($importer, $config);
148 196 } elseif ('csv' === $parser) {
149 197 return $this->get_csv_file($importer, $config);
198 + } elseif ('json' === $parser) {
199 + return $this->get_json_file($importer, $config);
150 200 }
151 201
152 202 return false;
153 203 }
@@ -157,8 +207,9 @@
157 207 $importer = $this->get_importer($id);
158 208 $file = new CSVFile($importer->getFile(), $config);
159 209 $file->setDelimiter($importer->getFileSetting('delimiter'));
160 210 $file->setEnclosure($importer->getFileSetting('enclosure'));
211 + $file->setEscape($importer->getFileSetting('escape', "\\"));
161 212 return $file;
162 213 }
163 214
164 215 public function get_xml_file($id, $config)
@@ -168,8 +219,16 @@
168 219 $file->setRecordPath($importer->getFileSetting('base_path'));
169 220 return $file;
170 221 }
171 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 +
172 231 public function preview_csv_file($id, $fields = [], $row = 0)
173 232 {
174 233 $importer = $this->get_importer($id);
175 234 $config = $this->get_config($importer, true);
@@ -193,8 +252,20 @@
193 252 $record = $parser->getRecord($row);
194 253 return $record->queryGroup(['fields' => $fields]);
195 254 }
196 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 +
197 268 public function process_csv_file($id, $delimiter, $enclosure, $tmp = false)
198 269 {
199 270 $importer = $this->get_importer($id);
200 271 $config = $this->get_config($importer->getId(), $tmp);
@@ -203,36 +274,8 @@
203 274 $file->setDelimiter($delimiter);
204 275 $file->setEnclosure($enclosure);
205 276 $file->processing(true);
206 277
207 - if (empty($importer->getMap())) {
208 -
209 - // we are on first file import
210 - $headings = str_getcsv($file->getRecord(0), $file->getDelimiter(), $file->getEnclosure());
211 - $headings = array_map('trim', $headings);
212 -
213 - $template = $this->get_importer_template($id);
214 - $field_map = $template->generate_field_map($headings, $importer);
215 - $field_map = apply_filters('iwp/importer/generate_field_map', $field_map, $headings, $importer);
216 -
217 - $map = $field_map['map'];
218 - foreach ($map as $key => $value) {
219 - $importer->setMap($key, $value);
220 - }
221 -
222 - $enabled = $field_map['enabled'];
223 - foreach ($enabled as $enabled_field) {
224 - $importer->setEnabled($enabled_field);
225 - }
226 -
227 - // Disabled due to testing:
228 - // https://localdev/wp-admin/tools.php?page=importwp&edit=29&step=1
229 - //
230 - // 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;}}
231 - //
232 - $importer->save();
233 - }
234 -
235 278 return $file->getRecordCount();
236 279 }
237 280
238 281 public function process_xml_file($id, $tmp = false)
@@ -257,8 +300,19 @@
257 300
258 301 return $results;
259 302 }
260 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 +
261 315 /**
262 316 * Link import file to importer via post meta
263 317 *
264 318 * @param ImporterModel $id
@@ -274,8 +328,15 @@
274 328 }
275 329
276 330 $index++;
277 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 +
278 339 update_post_meta($importer->getId(), '_importer_files', $index);
279 340 update_post_meta($importer->getId(), '_importer_file_' . $index, $file_path);
280 341 return $index;
281 342 }
@@ -289,11 +350,50 @@
289 350 $file_index = 1;
290 351 }
291 352 $file_index++;
292 353
293 - return $importer->getId() . '-' . intval($file_index) . '-';
354 + return $importer->getId() . '-' . intval($file_index) . '-' . wp_generate_password(12, false, false) . '-';
294 355 }
295 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 +
296 396 public function upload_file($id, $file)
297 397 {
298 398 $importer = $this->get_importer($id);
299 399 Logger::setId($importer->getId());
@@ -298,10 +398,22 @@
298 398 $importer = $this->get_importer($id);
299 399 Logger::setId($importer->getId());
300 400
301 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 +
302 412 $result = $this->filesystem->upload_file($file, $allowed_file_types);
303 413
414 + remove_filter('wp_handle_upload_prefilter', $prefix_upload);
415 +
304 416 if (is_wp_error($result)) {
305 417 return $result;
306 418 }
307 419
@@ -326,11 +438,12 @@
326 438 if (preg_match('/^s?ftp?:\/\//', $source) === 1) {
327 439
328 440 if (preg_match('/^(?<protocol>s?ftp):\/\/(?:(?<user>[^\:@]+)(?:\:(?<pass>[^@]+))?@)?(?<host>[^\:\/]+)(?:\:(?<port>[0-9]+))?(?:\/(?<path>.*))$/', $source, $matches) !== 1) {
329 441
330 - return new \WP_Error("IM_RM_FTP_PARSE", "Unable to parse FTP connection string");
442 + return new \WP_Error("IM_RM_FTP_PARSE", __("Unable to parse FTP connection string", 'jc-importer'));
331 443 }
332 444
445 + $protocol = isset($matches['protocol']) ? $matches['protocol'] : 'ftp';
333 446 $user = isset($matches['user']) ? urldecode($matches['user']) : '';
334 447 $pass = isset($matches['pass']) ? urldecode($matches['pass']) : '';
335 448 $host = isset($matches['host']) ? $matches['host'] : false;
336 449 $port = isset($matches['port']) && !empty($matches['port']) ? $matches['port'] : intval(21);
@@ -336,13 +449,13 @@
336 449 $port = isset($matches['port']) && !empty($matches['port']) ? $matches['port'] : intval(21);
337 450 $path = isset($matches['path']) ? $matches['path'] : false;
338 451
339 452 if (!$host) {
340 - return new \WP_Error("IM_RM_FTP_HOST", "Unable to parse ftp host from connection string");
453 + return new \WP_Error("IM_RM_FTP_HOST", __("Unable to parse ftp host from connection string", 'jc-importer'));
341 454 }
342 455
343 456 if (!$path) {
344 - return new \WP_Error("IM_RM_FTP_HOST", "Unable to parse ftp host from connection string");
457 + return new \WP_Error("IM_RM_FTP_HOST", __("Unable to parse ftp host from connection string", 'jc-importer'));
345 458 }
346 459
347 460 /**
348 461 * @var \ImportWP\Common\Ftp\Ftp $ftp
@@ -361,9 +474,35 @@
361 474 ];
362 475 $path = apply_filters(sprintf('iwp/importer/remote_file/source=%s', 'ftp'), $path, $importer, $filter_connection_args);
363 476 $path = apply_filters(sprintf('iwp/importer=%d/remote_file/source=ftp', $importer->getId(), 'ftp'), $path, $importer, $filter_connection_args);
364 477
365 - $result = $ftp->download_file($path, $host, $user, $pass, false, $port);
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 + }
366 505 } else {
367 506
368 507 $result = $this->filesystem->download_file($source, $filetype, $allowed_file_types, null, $prefix);
369 508 }
@@ -382,16 +521,34 @@
382 521
383 522 return $attachment_id;
384 523 }
385 524
386 - public function local_file($id, $source)
525 + public function local_file($id, $source, $filetype = null)
387 526 {
388 527 $importer = $this->get_importer($id);
389 528 Logger::setId($importer->getId());
390 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 +
391 548 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
392 549 $prefix = $this->get_importer_file_prefix($importer);
393 - $result = $this->filesystem->copy_file($source, $allowed_file_types, null, $prefix);
550 + $result = $this->filesystem->copy_file($source, $allowed_file_types, null, $prefix, $filetype);
394 551
395 552 if (is_wp_error($result)) {
396 553 return $result;
397 554 }
@@ -425,9 +582,9 @@
425 582 $file_path = apply_filters('iwp/importer/file_uploaded/file_path', $file_path, $importer_model);
426 583
427 584 $file_id = $this->link_importer_file($id, $file_path);
428 585 if (!$file_id) {
429 - 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'));
430 587 }
431 588
432 589 if (is_null($importer_model->getParser())) {
433 590 $importer_model->setParser($file_type);
@@ -488,9 +645,9 @@
488 645
489 646 $base .= str_pad($id, 2, STR_PAD_LEFT) . DIRECTORY_SEPARATOR;
490 647 if (!file_exists($base)) {
491 648 if (!is_writable(dirname($base)) || !mkdir($base)) {
492 - throw new \Exception("Unable to create directory: " . $base);
649 + throw new \Exception(sprintf(__("Unable to create directory: %s", 'jc-importer'), $base));
493 650 }
494 651 }
495 652
496 653 for ($i = 0; $i < ceil(strlen($session) / 2); $i++) {
@@ -497,9 +654,9 @@
497 654 $base .= substr($session, $i * 2, 2) . DIRECTORY_SEPARATOR;
498 655 if (!file_exists($base)) {
499 656
500 657 if (!is_writable(dirname($base)) || !mkdir($base)) {
501 - throw new \Exception("Unable to create directory: " . $base);
658 + throw new \Exception(sprintf(__("Unable to create directory: %s", 'jc-importer'), $base));
502 659 }
503 660 }
504 661
505 662 if ($i >= $max_depth - 2) {
@@ -532,9 +689,9 @@
532 689
533 690 // store current importer
534 691 iwp()->importer = $importer_data;
535 692
536 - $config_data = get_site_option('iwp_importer_config_' . $importer_id, []);
693 + $config_data = get_option('iwp_importer_config_' . $importer_id, []);
537 694
538 695 $this->event_handler->run('importer_manager.import', [$importer_data]);
539 696
540 697 $state = new ImporterState($importer_id, $user);
@@ -541,11 +698,16 @@
541 698
542 699 try {
543 700
544 701 Logger::debug('IM -init_state');
702 +
703 + // 1. Set State Session, and load its state
545 704 $state->init($session);
546 705
706 + // if this is a new session, clear config files
547 707 if ($state->has_status('init')) {
708 + // rest importer log.
709 + Logger::clear($importer_id);
548 710 Logger::debug('IM -clear_config_files');
549 711 $this->clear_config_files($importer_id, false, true);
550 712 $config_data['features'] = [
551 713 'session_table' => true
@@ -569,8 +731,9 @@
569 731 // mapper
570 732 Logger::debug('IM -get_importer_mapper');
571 733 $mapper = $this->get_importer_mapper($importer_data, $template, $permission);
572 734
735 + // if this is a new session, build config
573 736 if ($state->has_status('init')) {
574 737
575 738 Logger::debug('IM -generate_config');
576 739
@@ -599,8 +762,10 @@
599 762 $run_fetch_file = $importer_data->getSetting('run_fetch') || false;
600 763 $run_fetch_file = apply_filters('iwp/importer/run_fetch_file', $run_fetch_file);
601 764 if ($run_fetch_file) {
602 765
766 + add_filter('upload_dir', [$this, 'set_custom_upload_path']);
767 +
603 768 $datasource = $importer_data->getDatasource();
604 769 switch ($datasource) {
605 770 case 'remote':
606 771 $raw_source = $importer_data->getDatasourceSetting('remote_url');
@@ -611,18 +776,20 @@
611 776 case 'local':
612 777 $raw_source = $importer_data->getDatasourceSetting('local_url');
613 778 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer_data);
614 779 $source = apply_filters('iwp/importer/datasource/local', $source, $raw_source, $importer_data);
615 - $attachment_id = $this->local_file($importer_data, $source);
780 + $attachment_id = $this->local_file($importer_data, $source, $importer_data->getParser());
616 781 break;
617 782 default:
618 783 // TODO: record error
619 - $attachment_id = new \WP_Error('IWP_CRON_1', 'Unable to get new file using datasource: ' . $datasource);
784 + $attachment_id = new \WP_Error('IWP_CRON_1', sprintf(__('Unable to get new file using datasource: %s', 'jc-importer'), $datasource));
620 785 break;
621 786 }
622 787
788 + remove_filter('upload_dir', [$this, 'set_custom_upload_path']);
789 +
623 790 if (is_wp_error($attachment_id)) {
624 - throw new \Exception('Importer Datasource: ' . $attachment_id->get_error_message());
791 + throw new \Exception(sprintf(__('Importer Datasource: %s', 'jc-importer'), $attachment_id->get_error_message()));
625 792 }
626 793 }
627 794 }
628 795
@@ -641,12 +808,28 @@
641 808 Logger::debug('IM -get_xml_file');
642 809 $file = $this->get_xml_file($importer_data, $config);
643 810 Logger::debug('IM -load_parser');
644 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);
645 817 } else {
646 818 $parser = apply_filters('iwp/importer/init_parser', false, $importer_data, $config);
647 819 }
648 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
649 832 if ($state->has_status('init')) {
650 833
651 834 Logger::debug('IM -get_record_count');
652 835 $end = $parser->file()->getRecordCount();
@@ -659,9 +842,9 @@
659 842
660 843 $config_data['start'] = $this->get_start($importer_data, $start);
661 844 $config_data['end'] = $this->get_end($importer_data, $config_data['start'], $end);
662 845
663 - update_site_option('iwp_importer_config_' . $importer_id, $config_data);
846 + update_option('iwp_importer_config_' . $importer_id, $config_data);
664 847
665 848 Logger::debug('IM -update_state');
666 849 $state->update(function ($state) use ($config_data) {
667 850
@@ -679,8 +862,13 @@
679 862
680 863 do_action('iwp/importer/init', $importer_data);
681 864 }
682 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 +
683 871 Logger::debug('IM -import');
684 872 $importer = new \ImportWP\Common\Importer\Importer($config);
685 873 $importer->parser($parser);
686 874 $importer->mapper($mapper);
@@ -692,9 +880,11 @@
692 880 } catch (\Exception $e) {
693 881
694 882 // TODO: Missing template errors are currently not being logged to history, possibly others?
695 883 Logger::error('import -error=' . $e->getMessage(), $importer_id);
696 - return $state->error($e)->get_raw();
884 + $state->error($e);
885 + Util::write_status_session_to_file($id, $state);
886 + return $state->get_raw();
697 887 }
698 888
699 889 /**
700 890 * @var Properties $properties
@@ -714,8 +904,38 @@
714 904 return $data;
715 905 })->get_raw();
716 906 }
717 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 +
718 938 public function get_start($importer_data, $start)
719 939 {
720 940 $tmp_start = $importer_data->getStartRow();
721 941 if (!is_null($tmp_start) && "" !== $tmp_start) {
@@ -748,9 +968,9 @@
748 968 $templates = $this->get_templates();
749 969 $template_name = $importer_model->getTemplate();
750 970
751 971 if (!isset($templates[$template_name])) {
752 - $exception_msg = "Unable to locate importer template: " . $template_name;
972 + $exception_msg = sprintf(__("Unable to locate importer template: %s", 'jc-importer'), $template_name);
753 973 Logger::error('import -get_importer_template=' . $exception_msg, $importer_model->getId());
754 974 throw new \Exception($exception_msg);
755 975 }
756 976
@@ -790,9 +1010,9 @@
790 1010 public function get_mapper($key)
791 1011 {
792 1012 $mappers = $this->get_mappers();
793 1013 if (!isset($mappers[$key])) {
794 - 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));
795 1015 }
796 1016
797 1017 return $mappers[$key];
798 1018 }
@@ -815,9 +1035,9 @@
815 1035 public function get_template($key)
816 1036 {
817 1037 $templates = $this->get_templates();
818 1038 if (!isset($templates[$key])) {
819 - 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));
820 1040 }
821 1041
822 1042 return $templates[$key];
823 1043 }