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 +364 -14 2.7.1 → 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);
@@ -224,8 +300,19 @@
224 300
225 301 return $results;
226 302 }
227 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 +
228 315 /**
229 316 * Link import file to importer via post meta
230 317 *
231 318 * @param ImporterModel $id
@@ -241,8 +328,15 @@
241 328 }
242 329
243 330 $index++;
244 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 +
245 339 update_post_meta($importer->getId(), '_importer_files', $index);
246 340 update_post_meta($importer->getId(), '_importer_file_' . $index, $file_path);
247 341 return $index;
248 342 }
@@ -256,11 +350,50 @@
256 350 $file_index = 1;
257 351 }
258 352 $file_index++;
259 353
260 - return $importer->getId() . '-' . intval($file_index) . '-';
354 + return $importer->getId() . '-' . intval($file_index) . '-' . wp_generate_password(12, false, false) . '-';
261 355 }
262 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 +
263 396 public function upload_file($id, $file)
264 397 {
265 398 $importer = $this->get_importer($id);
266 399 Logger::setId($importer->getId());
@@ -265,10 +398,22 @@
265 398 $importer = $this->get_importer($id);
266 399 Logger::setId($importer->getId());
267 400
268 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 +
269 412 $result = $this->filesystem->upload_file($file, $allowed_file_types);
270 413
414 + remove_filter('wp_handle_upload_prefilter', $prefix_upload);
415 +
271 416 if (is_wp_error($result)) {
272 417 return $result;
273 418 }
274 419
@@ -286,10 +431,86 @@
286 431 Logger::setId($importer->getId());
287 432
288 433 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
289 434 $prefix = $this->get_importer_file_prefix($importer);
290 - $result = $this->filesystem->download_file($source, $filetype, $allowed_file_types, null, $prefix);
291 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 +
292 513 if (is_wp_error($result)) {
293 514 return $result;
294 515 }
295 516
@@ -300,16 +521,34 @@
300 521
301 522 return $attachment_id;
302 523 }
303 524
304 - public function local_file($id, $source)
525 + public function local_file($id, $source, $filetype = null)
305 526 {
306 527 $importer = $this->get_importer($id);
307 528 Logger::setId($importer->getId());
308 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 +
309 548 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
310 549 $prefix = $this->get_importer_file_prefix($importer);
311 - $result = $this->filesystem->copy_file($source, $allowed_file_types, null, $prefix);
550 + $result = $this->filesystem->copy_file($source, $allowed_file_types, null, $prefix, $filetype);
312 551
313 552 if (is_wp_error($result)) {
314 553 return $result;
315 554 }
@@ -343,9 +582,9 @@
343 582 $file_path = apply_filters('iwp/importer/file_uploaded/file_path', $file_path, $importer_model);
344 583
345 584 $file_id = $this->link_importer_file($id, $file_path);
346 585 if (!$file_id) {
347 - 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'));
348 587 }
349 588
350 589 if (is_null($importer_model->getParser())) {
351 590 $importer_model->setParser($file_type);
@@ -406,9 +645,9 @@
406 645
407 646 $base .= str_pad($id, 2, STR_PAD_LEFT) . DIRECTORY_SEPARATOR;
408 647 if (!file_exists($base)) {
409 648 if (!is_writable(dirname($base)) || !mkdir($base)) {
410 - throw new \Exception("Unable to create directory: " . $base);
649 + throw new \Exception(sprintf(__("Unable to create directory: %s", 'jc-importer'), $base));
411 650 }
412 651 }
413 652
414 653 for ($i = 0; $i < ceil(strlen($session) / 2); $i++) {
@@ -415,9 +654,9 @@
415 654 $base .= substr($session, $i * 2, 2) . DIRECTORY_SEPARATOR;
416 655 if (!file_exists($base)) {
417 656
418 657 if (!is_writable(dirname($base)) || !mkdir($base)) {
419 - throw new \Exception("Unable to create directory: " . $base);
658 + throw new \Exception(sprintf(__("Unable to create directory: %s", 'jc-importer'), $base));
420 659 }
421 660 }
422 661
423 662 if ($i >= $max_depth - 2) {
@@ -447,10 +686,13 @@
447 686
448 687 $importer_data = $this->get_importer($id);
449 688 $importer_id = $importer_data->getId();
450 689
451 - $config_data = get_site_option('iwp_importer_config_' . $importer_id, []);
690 + // store current importer
691 + iwp()->importer = $importer_data;
452 692
693 + $config_data = get_option('iwp_importer_config_' . $importer_id, []);
694 +
453 695 $this->event_handler->run('importer_manager.import', [$importer_data]);
454 696
455 697 $state = new ImporterState($importer_id, $user);
456 698
@@ -456,11 +698,16 @@
456 698
457 699 try {
458 700
459 701 Logger::debug('IM -init_state');
702 +
703 + // 1. Set State Session, and load its state
460 704 $state->init($session);
461 705
706 + // if this is a new session, clear config files
462 707 if ($state->has_status('init')) {
708 + // rest importer log.
709 + Logger::clear($importer_id);
463 710 Logger::debug('IM -clear_config_files');
464 711 $this->clear_config_files($importer_id, false, true);
465 712 $config_data['features'] = [
466 713 'session_table' => true
@@ -484,8 +731,9 @@
484 731 // mapper
485 732 Logger::debug('IM -get_importer_mapper');
486 733 $mapper = $this->get_importer_mapper($importer_data, $template, $permission);
487 734
735 + // if this is a new session, build config
488 736 if ($state->has_status('init')) {
489 737
490 738 Logger::debug('IM -generate_config');
491 739
@@ -505,8 +753,45 @@
505 753 $version = 0;
506 754 }
507 755 update_post_meta($importer_id, '_iwp_version', $version);
508 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 + }
509 794 }
510 795
511 796 $start = 0;
512 797
@@ -523,21 +808,43 @@
523 808 Logger::debug('IM -get_xml_file');
524 809 $file = $this->get_xml_file($importer_data, $config);
525 810 Logger::debug('IM -load_parser');
526 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);
527 817 } else {
528 818 $parser = apply_filters('iwp/importer/init_parser', false, $importer_data, $config);
529 819 }
530 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
531 832 if ($state->has_status('init')) {
532 833
533 834 Logger::debug('IM -get_record_count');
534 835 $end = $parser->file()->getRecordCount();
535 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 +
536 843 $config_data['start'] = $this->get_start($importer_data, $start);
537 844 $config_data['end'] = $this->get_end($importer_data, $config_data['start'], $end);
538 845
539 - update_site_option('iwp_importer_config_' . $importer_id, $config_data);
846 + update_option('iwp_importer_config_' . $importer_id, $config_data);
540 847
541 848 Logger::debug('IM -update_state');
542 849 $state->update(function ($state) use ($config_data) {
543 850
@@ -551,10 +858,17 @@
551 858 });
552 859
553 860 Logger::debug('IM -write_status_session_to_file');
554 861 Util::write_status_session_to_file($id, $state);
862 +
863 + do_action('iwp/importer/init', $importer_data);
555 864 }
556 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 +
557 871 Logger::debug('IM -import');
558 872 $importer = new \ImportWP\Common\Importer\Importer($config);
559 873 $importer->parser($parser);
560 874 $importer->mapper($mapper);
@@ -566,9 +880,11 @@
566 880 } catch (\Exception $e) {
567 881
568 882 // TODO: Missing template errors are currently not being logged to history, possibly others?
569 883 Logger::error('import -error=' . $e->getMessage(), $importer_id);
570 - return $state->error($e)->get_raw();
884 + $state->error($e);
885 + Util::write_status_session_to_file($id, $state);
886 + return $state->get_raw();
571 887 }
572 888
573 889 /**
574 890 * @var Properties $properties
@@ -588,8 +904,38 @@
588 904 return $data;
589 905 })->get_raw();
590 906 }
591 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 +
592 938 public function get_start($importer_data, $start)
593 939 {
594 940 $tmp_start = $importer_data->getStartRow();
595 941 if (!is_null($tmp_start) && "" !== $tmp_start) {
@@ -622,9 +968,9 @@
622 968 $templates = $this->get_templates();
623 969 $template_name = $importer_model->getTemplate();
624 970
625 971 if (!isset($templates[$template_name])) {
626 - $exception_msg = "Unable to locate importer template: " . $template_name;
972 + $exception_msg = sprintf(__("Unable to locate importer template: %s", 'jc-importer'), $template_name);
627 973 Logger::error('import -get_importer_template=' . $exception_msg, $importer_model->getId());
628 974 throw new \Exception($exception_msg);
629 975 }
630 976
@@ -653,9 +999,11 @@
653 999 $mappers = $this->event_handler->run('mappers.register', [[]]); // apply_filters('iwp/mappers/register', []);
654 1000 $mappers = array_merge($mappers, [
655 1001 'post' => PostMapper::class,
656 1002 'user' => UserMapper::class,
657 - 'term' => TermMapper::class
1003 + 'term' => TermMapper::class,
1004 + 'attachment' => AttachmentMapper::class,
1005 + 'comment' => CommentMapper::class,
658 1006 ]);
659 1007 return $mappers;
660 1008 }
661 1009
@@ -662,9 +1010,9 @@
662 1010 public function get_mapper($key)
663 1011 {
664 1012 $mappers = $this->get_mappers();
665 1013 if (!isset($mappers[$key])) {
666 - 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));
667 1015 }
668 1016
669 1017 return $mappers[$key];
670 1018 }
@@ -676,8 +1024,10 @@
676 1024 'post' => PostTemplate::class,
677 1025 'page' => PageTemplate::class,
678 1026 'user' => UserTemplate::class,
679 1027 'term' => TermTemplate::class,
1028 + 'attachment' => AttachmentTemplate::class,
1029 + 'comment' => CommentTemplate::class,
680 1030 'custom-post-type' => CustomPostTypeTemplate::class,
681 1031 ]);
682 1032 return $templates;
683 1033 }
@@ -685,9 +1035,9 @@
685 1035 public function get_template($key)
686 1036 {
687 1037 $templates = $this->get_templates();
688 1038 if (!isset($templates[$key])) {
689 - 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));
690 1040 }
691 1041
692 1042 return $templates[$key];
693 1043 }