PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.7.12
Import WP – CSV & XML Import Export for WordPress v2.7.12
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
jc-importer / class / Common / Rest / RestManager.php

RestManager.php in Import WP – CSV & XML Import Export for WordPress 2.7.12, at class/Common/Rest/RestManager.php

1,510 lines 53.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImportWP\Common\Rest;
4
5 use ImportWP\Common\Exporter\ExporterManager;
6 use ImportWP\Common\Exporter\State\ExporterState;
7 use ImportWP\Common\Filesystem\Filesystem;
8 use ImportWP\Common\Http\Http;
9 use ImportWP\Common\Importer\ImporterManager;
10 use ImportWP\Common\Importer\Preview\CSVPreview;
11 use ImportWP\Common\Importer\Preview\XMLPreview;
12 use ImportWP\Common\Importer\State\ImporterState;
13 use ImportWP\Common\Importer\Template\Template;
14 use ImportWP\Common\Importer\Template\TemplateManager;
15 use ImportWP\Common\Migration\Migrations;
16 use ImportWP\Common\Model\ExporterModel;
17 use ImportWP\Common\Model\ImporterModel;
18 use ImportWP\Common\Properties\Properties;
19 use ImportWP\Common\Util\Logger;
20 use ImportWP\Common\Util\Util;
21 use ImportWP\Container;
22 use ImportWP\EventHandler;
23
24 class RestManager extends \WP_REST_Controller
25 {
26 /**
27 * @var Properties
28 */
29 protected $properties;
30
31 /**
32 * @var Http
33 */
34 protected $http;
35
36 /**
37 * @var Filesystem
38 */
39 protected $filesystem;
40
41 /**
42 * @var ImporterManager
43 */
44 protected $importer_manager;
45
46 /**
47 * @var ExporterManager
48 */
49 protected $exporter_manager;
50
51 /**
52 * @var TemplateManager $template_manager
53 */
54 protected $template_manager;
55
56 /**
57 * @var EventHandler
58 */
59 protected $event_handler;
60
61 public function __construct(ImporterManager $importer_manager, ExporterManager $exporter_manager, Properties $properties, Http $http, Filesystem $filesystem, TemplateManager $template_manager, $event_handler)
62 {
63 $this->importer_manager = $importer_manager;
64 $this->exporter_manager = $exporter_manager;
65 $this->properties = $properties;
66 $this->http = $http;
67 $this->filesystem = $filesystem;
68 $this->template_manager = $template_manager;
69 $this->event_handler = $event_handler;
70 }
71
72 public function register()
73 {
74 add_action('rest_api_init', array($this, 'register_routes'));
75 }
76
77 public function register_routes()
78 {
79 $namespace = $this->properties->rest_namespace . '/' . $this->properties->rest_version;
80
81 register_rest_route($namespace, '/system/check', array(
82 array(
83 'methods' => \WP_REST_Server::READABLE,
84 'callback' => array($this, 'check_rest_status'),
85 'permission_callback' => array($this, 'get_permission')
86 )
87 ));
88 register_rest_route($namespace, '/system/migrate', array(
89 array(
90 'methods' => \WP_REST_Server::READABLE,
91 'callback' => array($this, 'migrate'),
92 'permission_callback' => array($this, 'get_permission')
93 )
94 ));
95
96 register_rest_route($namespace, '/importer', array(
97 array(
98 'methods' => \WP_REST_Server::CREATABLE,
99 'callback' => array($this, 'save_importer'),
100 'permission_callback' => array($this, 'get_permission')
101 )
102 ));
103
104 register_rest_route($namespace, '/importers', array(
105 array(
106 'methods' => \WP_REST_Server::READABLE,
107 'callback' => array($this, 'get_importers'),
108 'permission_callback' => array($this, 'get_permission')
109 ),
110 ));
111
112 register_rest_route($namespace, '/status', array(
113 array(
114 'methods' => \WP_REST_Server::READABLE,
115 'callback' => array($this, 'get_status'),
116 'permission_callback' => array($this, 'get_permission')
117 ),
118 ));
119
120 register_rest_route($namespace, '/importer/(?P<id>\d+)', array(
121 array(
122 'methods' => \WP_REST_Server::READABLE,
123 'callback' => array($this, 'get_importer'),
124 'permission_callback' => array($this, 'get_permission')
125 ),
126 array(
127 'methods' => \WP_REST_Server::EDITABLE,
128 'callback' => array($this, 'save_importer'),
129 'permission_callback' => array($this, 'get_permission')
130 ),
131 array(
132 'methods' => \WP_REST_Server::DELETABLE,
133 'callback' => array($this, 'delete_importer'),
134 'permission_callback' => array($this, 'get_permission')
135 ),
136 ));
137
138 register_rest_route($namespace, '/importer/(?P<id>\d+)/upload', array(
139 array(
140 'methods' => \WP_REST_Server::EDITABLE,
141 'callback' => array($this, 'attach_file'),
142 'permission_callback' => array($this, 'get_permission')
143 )
144 ));
145
146 register_rest_route($namespace, '/importer/(?P<id>\d+)/file-process', array(
147 array(
148 'methods' => \WP_REST_Server::CREATABLE,
149 'callback' => array($this, 'get_file_process'),
150 'permission_callback' => array($this, 'get_permission')
151 )
152 ));
153
154 register_rest_route($namespace, '/importer/(?P<id>\d+)/file-preview', array(
155 array(
156 'methods' => \WP_REST_Server::CREATABLE,
157 'callback' => array($this, 'get_file_preview'),
158 'permission_callback' => array($this, 'get_permission')
159 )
160 ));
161
162 register_rest_route($namespace, '/importer/(?P<id>\d+)/preview', array(
163 array(
164 'methods' => \WP_REST_Server::CREATABLE,
165 'callback' => array($this, 'get_preview'),
166 'permission_callback' => array($this, 'get_permission')
167 )
168 ));
169
170 register_rest_route($namespace, '/importer/(?P<id>\d+)/init', array(
171 array(
172 'methods' => \WP_REST_Server::READABLE,
173 'callback' => array($this, 'init_import'),
174 'permission_callback' => array($this, 'get_permission')
175 )
176 ));
177
178 register_rest_route($namespace, '/importer/(?P<id>\d+)/run', array(
179 array(
180 'methods' => \WP_REST_Server::CREATABLE,
181 'callback' => array($this, 'run_import'),
182 'permission_callback' => array($this, 'get_permission')
183 )
184 ));
185
186 register_rest_route($namespace, '/importer/(?P<id>\d+)/pause', array(
187 array(
188 'methods' => \WP_REST_Server::CREATABLE,
189 'callback' => array($this, 'pause_import'),
190 'permission_callback' => array($this, 'get_permission')
191 )
192 ));
193
194 register_rest_route($namespace, '/importer/(?P<id>\d+)/stop', array(
195 array(
196 'methods' => \WP_REST_Server::CREATABLE,
197 'callback' => array($this, 'stop_import'),
198 'permission_callback' => array($this, 'get_permission')
199 )
200 ));
201
202 register_rest_route($namespace, '/importer/(?P<id>\d+)/field', array(
203 array(
204 'methods' => \WP_REST_Server::CREATABLE,
205 'callback' => array($this, 'get_template_field_options'),
206 'permission_callback' => array($this, 'get_permission')
207 )
208 ));
209
210 register_rest_route($namespace, '/importer/(?P<id>\d+)/logs/(?P<session>\S+)', array(
211 array(
212 'methods' => \WP_REST_Server::READABLE,
213 'callback' => array($this, 'get_log'),
214 'permission_callback' => array($this, 'get_permission')
215 )
216 ));
217
218 register_rest_route($namespace, '/importer/(?P<id>\d+)/logs', array(
219 array(
220 'methods' => \WP_REST_Server::READABLE,
221 'callback' => array($this, 'get_logs'),
222 'permission_callback' => array($this, 'get_permission')
223 )
224 ));
225
226 register_rest_route($namespace, '/settings', array(
227 array(
228 'methods' => \WP_REST_Server::CREATABLE,
229 'callback' => array($this, 'save_settings'),
230 'permission_callback' => array($this, 'get_permission')
231 ),
232 array(
233 'methods' => \WP_REST_Server::READABLE,
234 'callback' => array($this, 'get_settings'),
235 'permission_callback' => array($this, 'get_permission')
236 ),
237 ));
238
239 register_rest_route($namespace, '/import-export', array(
240 array(
241 'methods' => \WP_REST_Server::CREATABLE,
242 'callback' => array($this, 'import_exporters'),
243 'permission_callback' => array($this, 'get_permission')
244 ),
245 array(
246 'methods' => \WP_REST_Server::READABLE,
247 'callback' => array($this, 'export_importers'),
248 'permission_callback' => array($this, 'get_permission')
249 ),
250 ));
251
252 register_rest_route($namespace, '/importer/(?P<id>\d+)/debug_log', array(
253 array(
254 'methods' => \WP_REST_Server::READABLE,
255 'callback' => array($this, 'get_debug_log'),
256 'permission_callback' => array($this, 'get_permission')
257 )
258 ));
259
260 register_rest_route($namespace, '/importer/(?P<id>\d+)/template', array(
261 array(
262 'methods' => \WP_REST_Server::READABLE,
263 'callback' => array($this, 'get_template'),
264 'permission_callback' => array($this, 'get_permission')
265 )
266 ));
267
268 // Exporter
269
270 register_rest_route($namespace, '/exporter', array(
271 array(
272 'methods' => \WP_REST_Server::CREATABLE,
273 'callback' => array($this, 'save_exporter'),
274 'permission_callback' => array($this, 'get_permission')
275 )
276 ));
277
278 register_rest_route($namespace, '/exporters', array(
279 array(
280 'methods' => \WP_REST_Server::READABLE,
281 'callback' => array($this, 'get_exporters'),
282 'permission_callback' => array($this, 'get_permission')
283 ),
284 ));
285
286 register_rest_route($namespace, '/exporter/(?P<id>\d+)', array(
287 array(
288 'methods' => \WP_REST_Server::READABLE,
289 'callback' => array($this, 'get_exporter'),
290 'permission_callback' => array($this, 'get_permission')
291 ),
292 array(
293 'methods' => \WP_REST_Server::EDITABLE,
294 'callback' => array($this, 'save_exporter'),
295 'permission_callback' => array($this, 'get_permission')
296 ),
297 array(
298 'methods' => \WP_REST_Server::DELETABLE,
299 'callback' => array($this, 'delete_exporter'),
300 'permission_callback' => array($this, 'get_permission')
301 ),
302 ));
303
304 register_rest_route($namespace, '/exporter/(?P<id>\d+)/init', array(
305 array(
306 'methods' => \WP_REST_Server::READABLE,
307 'callback' => array($this, 'init_export'),
308 'permission_callback' => array($this, 'get_permission')
309 )
310 ));
311
312 register_rest_route($namespace, '/exporter/(?P<id>\d+)/run', array(
313 array(
314 'methods' => \WP_REST_Server::CREATABLE,
315 'callback' => array($this, 'run_exporter'),
316 'permission_callback' => array($this, 'get_permission')
317 ),
318 ));
319
320 register_rest_route($namespace, '/exporter/status', array(
321 array(
322 'methods' => \WP_REST_Server::READABLE,
323 'callback' => array($this, 'get_exporter_status'),
324 'permission_callback' => array($this, 'get_permission')
325 ),
326 ));
327 }
328
329 public function get_permission()
330 {
331
332 if (!current_user_can('manage_options')) {
333 return new \WP_Error('rest_forbidden', esc_html__('You do not have permissions.', $this->properties->plugin_domain), array('status' => 401));
334 }
335
336 return true;
337 }
338
339 public function sanitize($data, $name = null, $path = [])
340 {
341 $path[] = $name;
342
343 if (is_array($data)) {
344 foreach ($data as $k => $v) {
345 $data[$k] = $this->sanitize($v, $k, $path);
346 }
347
348 return $data;
349 }
350
351 $full_path = implode('.', array_filter($path));
352 if (!is_null($full_path)) {
353
354 if (preg_match('/^map\.\S+/', $full_path) !== false) {
355 return $data;
356 }
357 }
358
359 if (!is_null($name)) {
360 switch ($name) {
361 case 'id':
362 return intval($data);
363 }
364 }
365
366 return sanitize_text_field($data);
367 }
368
369 public function check_rest_status(\WP_REST_Request $request)
370 {
371 $result = [];
372 // find required php ext: https://github.com/llaville/php-compat-info
373
374 $tmp_writable = wp_is_writable($this->filesystem->get_temp_directory());
375
376
377 $result = [
378 'tmp_writable' => [
379 'status' => $tmp_writable ? 'yes' : 'no',
380 'message' => $tmp_writable ? '' : 'WordPress is unable to write to directory: ' . $this->filesystem->get_temp_directory() . ', make sure this directory is writable.',
381 ],
382 'rest_enabled' => [
383 'status' => 'yes',
384 'message' => '',
385 ],
386 'ext_simplexml' => [
387 'status' => extension_loaded('SimpleXML') ? 'yes' : 'no',
388 'message' => '',
389 ],
390 'ext_mbstring' => [
391 'status' => extension_loaded('mbstring') ? 'yes' : 'no',
392 'message' => '',
393 ],
394 'ext_xmlreader' => [
395 'status' => extension_loaded('xmlreader') ? 'yes' : 'no',
396 'message' => '',
397 ],
398 'php_version' => [
399 'status' => version_compare(phpversion(), '5.5.0') ? 'yes' : 'no',
400 'message' => '',
401 ],
402 ];
403 return $this->http->end_rest_success($result);
404 }
405
406 public function migrate(\WP_REST_Request $request)
407 {
408 $migration = new Migrations();
409 $result = $migration->migrate();
410
411 return $this->http->end_rest_success("Migration Complete.");
412 }
413
414 public function get_importers(\WP_REST_Request $request)
415 {
416 $importers = $this->importer_manager->get_importers();
417 $result = [];
418
419 foreach ($importers as $importer) {
420 $result[] = $importer->data();
421 }
422
423 return $this->http->end_rest_success($result);
424 }
425
426 public function get_importer(\WP_REST_Request $request)
427 {
428 Logger::setRequestType('get_importer');
429
430 $id = intval($request->get_param('id'));
431 $importer_data = $this->importer_manager->get_importer($id);
432 $response = $importer_data->data('public');
433 return $this->http->end_rest_success($response);
434 }
435
436 public function save_importer(\WP_REST_Request $request)
437 {
438 Logger::setRequestType('save_importer');
439
440 $post_data = $request->get_body_params();
441 $id = isset($post_data['id']) ? intval($post_data['id']) : null;
442
443 $temp_post_data = [
444 'create' => [],
445 'update' => []
446 ];
447
448 if (isset($post_data['permissions'])) {
449 // TODO: update sanitize method to keep track of hierarchy
450 $temp_post_data['create'] = explode("\n", $post_data['permissions']['create']['fields']);
451 $temp_post_data['update'] = explode("\n", $post_data['permissions']['update']['fields']);
452 }
453
454 $post_data = $this->sanitize($post_data);
455
456 if (isset($post_data['permissions'])) {
457 // TODO: Method to bypass sanitization not needed once sanitize method has been upgraded
458 foreach (['create', 'update'] as $permission_method) {
459 $permission_fields = $temp_post_data[$permission_method];
460 if (!empty($permission_fields)) {
461 $post_data['permissions'][$permission_method]['fields'] = array_values(array_filter(array_map([$this, 'sanitize'], $permission_fields, array_fill(0, count($permission_fields), 'permission_' . $permission_method . '_fields'))));
462 } else {
463 $post_data['permissions'][$permission_method]['fields'] = [];
464 }
465 }
466 }
467
468
469
470 $importer = new ImporterModel($id, $this->importer_manager->is_debug());
471
472 if (isset($post_data['datasource'])) {
473 $importer->setDatasource($post_data['datasource']);
474 }
475
476 if (isset($post_data['remote_url'])) {
477 $importer->setDatasourceSetting('remote_url', $post_data['remote_url']);
478 }
479
480 if (isset($post_data['local_url'])) {
481 $importer->setDatasourceSetting('local_url', $post_data['local_url']);
482 }
483
484 if (isset($post_data['existing_id'])) {
485 $importer->setFileId(intval($post_data['existing_id']));
486 }
487
488 if (isset($post_data['template'], $post_data['template_type'])) {
489 $importer->setTemplate($post_data['template'], $post_data['template_type']);
490
491 // Get default template options
492 $template_class = $this->importer_manager->get_template($post_data['template']);
493
494 /**
495 * @var Template $template
496 */
497 $template = $this->template_manager->load_template($template_class);
498 $template_options = $template->get_default_template_options();
499
500 if (isset($post_data['template_options'])) {
501 $template_options = array_merge($template_options, $post_data['template_options']);
502 }
503
504 foreach ($template_options as $key => $val) {
505 $importer->setSetting($key, $val);
506 }
507 }
508
509 if (isset($post_data['name'])) {
510 $importer->setName($post_data['name']);
511 }
512
513 if (isset($post_data['setting_start_row'])) {
514 $importer->setStartRow($post_data['setting_start_row']);
515 }
516
517 if (isset($post_data['setting_max_row'])) {
518 $importer->setMaxRow($post_data['setting_max_row']);
519 }
520
521 // save settings
522 foreach ($post_data as $key => $value) {
523 if (1 === preg_match('/^setting_(?<key>.*)/', $key, $matches)) {
524
525 $value = $this->sanitize_setting($value);
526 $importer->setSetting($matches['key'], $value);
527 }
528 }
529
530 $parser = $importer->getParser();
531
532 if (isset($post_data['file_settings_encoding'])) {
533 $importer->setFileSetting('file_encoding', $post_data['file_settings_encoding']);
534 }
535
536 if ($parser === 'csv') {
537
538 $clear_config = false;
539 if (isset($post_data['file_settings_delimiter'])) {
540
541 $old_delimiter = $importer->getFileSetting('delimiter');
542 if ($old_delimiter !== $post_data['file_settings_delimiter']) {
543 $clear_config = true;
544 }
545 $importer->setFileSetting('delimiter', $post_data['file_settings_delimiter']);
546 }
547 if (isset($post_data['file_settings_enclosure'])) {
548 $old_enclosure = $importer->getFileSetting('enclosure');
549 if ($old_enclosure !== $post_data['file_settings_enclosure']) {
550 $clear_config = true;
551 }
552 $importer->setFileSetting('enclosure', $post_data['file_settings_enclosure']);
553 }
554 if (isset($post_data['file_settings_show_headings'])) {
555 $importer->setFileSetting('show_headings', $post_data['file_settings_show_headings'] === 'true' || $post_data['file_settings_show_headings'] === true ? true : false);
556 }
557
558 if ($clear_config) {
559 $this->importer_manager->clear_config_files($importer->getId(), true);
560 }
561 } elseif ($parser === 'xml') {
562 if (isset($post_data['file_settings_base_path'])) {
563 $importer->setFileSetting('base_path', $post_data['file_settings_base_path']);
564 }
565 }
566
567 if (isset($post_data['file_settings_setup'])) {
568 $importer->setFileSetting('setup', $post_data['file_settings_setup'] === 'true' ? true : false);
569 }
570
571 if (isset($post_data['map']) && is_array($post_data['map'])) {
572 foreach ($post_data['map'] as $key => $value) {
573
574 if (1 === preg_match('/\._index$/', $key)) {
575 $value = intval($value);
576 }
577
578 $importer->setMap($key, $value);
579 }
580 }
581
582 if (isset($post_data['enabled']) && is_array($post_data['enabled'])) {
583 foreach ($post_data['enabled'] as $key => $value) {
584 if ($value === 'true') {
585 $importer->setEnabled($key);
586 } else {
587 $importer->setEnabled($key, false);
588 }
589 }
590 }
591
592 if (isset($post_data['permissions']) && is_array($post_data['permissions'])) {
593
594 // create
595 if (isset($post_data['permissions']['create'])) {
596 $create = $post_data['permissions']['create'];
597 $importer->setPermission('create', [
598 'enabled' => isset($create['enabled']) && $create['enabled'] === 'true' ? true : false,
599 'type' => isset($create['type']) && in_array($create['type'], ['include', 'exclude'], true) ? $create['type'] : null,
600 'fields' => isset($create['fields']) ? $create['fields'] : [],
601 ]);
602 }
603
604 // update
605 if (isset($post_data['permissions']['update'])) {
606 $update = $post_data['permissions']['update'];
607 $importer->setPermission('update', [
608 'enabled' => isset($update['enabled']) && $update['enabled'] === 'true' ? true : false,
609 'type' => isset($update['type']) && in_array($update['type'], ['include', 'exclude'], true) ? $update['type'] : null,
610 'fields' => isset($update['fields']) ? $update['fields'] : [],
611 ]);
612 }
613
614 // remove
615 if (isset($post_data['permissions']['remove'])) {
616 $importer->setPermission('remove', [
617 'enabled' => $post_data['permissions']['remove']['enabled'] === 'true',
618 'trash' => $post_data['permissions']['remove']['trash'] === 'true',
619 ]);
620 }
621 }
622
623 $result = $importer->save();
624 if (is_wp_error($result)) {
625 return $this->http->end_rest_error($result->get_error_message());
626 }
627 return $this->http->end_rest_success($importer->data());
628 }
629
630 private function sanitize_setting($value)
631 {
632 if (is_array($value)) {
633 foreach ($value as &$tmp) {
634 $tmp = $this->sanitize_setting($tmp);
635 }
636 return $value;
637 } else {
638 if (in_array($value, ['true', 'false'], true)) {
639 if ($value === 'true') {
640 $value = true;
641 } else {
642 $value = false;
643 }
644 }
645 }
646
647 return $value;
648 }
649
650 public function get_status(\WP_REST_Request $request)
651 {
652 $this->http->set_stream_headers();
653
654 Logger::disable();
655
656 $importer_ids = $request->get_param('ids');
657
658 $result = [];
659
660 $query_data = array(
661 'post_type' => IWP_POST_TYPE,
662 'posts_per_page' => -1,
663 'fields' => 'ids'
664 );
665 if (!empty($importer_ids)) {
666 $query_data['post__in'] = $importer_ids;
667 }
668
669 $query = new \WP_Query($query_data);
670
671 foreach ($query->posts as $importer_id) {
672
673 $importer_model = $this->importer_manager->get_importer($importer_id);
674
675 $output = ImporterState::get_state($importer_id);
676 $output['version'] = 2;
677 $output['message'] = $this->generate_status_message($output);
678 $output['importer'] = $importer_id;
679
680 $result[] = $this->event_handler->run('iwp/importer/status/output', [$output, $importer_model]);
681 }
682
683 echo json_encode($result) . "\n";
684 die();
685 }
686
687 /**
688 * @param array $data
689 * @return string
690 */
691 protected function generate_status_message($data)
692 {
693 $output = '';
694
695 if (!$data || !isset($data['status']) || is_null($data['status']) || empty($data['status'])) {
696 return '';
697 }
698
699 if (isset($data['status'])) {
700 switch ($data['status']) {
701 case 'cancelled':
702 $output .= 'Import cancelled';
703 break;
704 case 'complete':
705 $output .= 'Import complete';
706 break;
707 case 'error':
708 $output = $data['message'];
709 return $output;
710 break;
711 }
712 }
713
714 if (isset($data['status']) && $data['status'] === 'running' && isset($data['section'])) {
715 switch ($data['section']) {
716 case 'import':
717 case 'delete':
718 $output = $data['section'] === 'import' ? 'Importing: ' : 'Deleting: ';
719 $output .= $data['progress'][$data['section']]['current_row'] . ' / ' . ($data['progress'][$data['section']]['end'] - $data['progress'][$data['section']]['start']);
720
721 break;
722 }
723 }
724
725 if (isset($data['stats'])) {
726 if ($data['stats']['inserts'] > 0) {
727 $output .= sprintf(', Inserts: %d', $data['stats']['inserts']);
728 }
729 if ($data['stats']['updates'] > 0) {
730 $output .= sprintf(', Updates: %d', $data['stats']['updates']);
731 }
732 if ($data['stats']['deletes'] > 0) {
733 $output .= sprintf(', Deletes: %d', $data['stats']['deletes']);
734 }
735 if ($data['stats']['skips'] > 0) {
736 $output .= sprintf(', Skips: %d', $data['stats']['skips']);
737 }
738 if ($data['stats']['errors'] > 0) {
739 $output .= sprintf(', Errors: %d', $data['stats']['errors']);
740 }
741 }
742
743 if (isset($data['timestamp'], $data['updated'])) {
744 /**
745 * @var Util $util
746 */
747 $util = Container::getInstance()->get('util');
748 $output .= ', Run Time: ' . $util->format_time($data['updated'] - $data['timestamp']);
749 } elseif (isset($data['duration'])) {
750 /**
751 * @var Util $util
752 */
753 $util = Container::getInstance()->get('util');
754 $output .= ', Run Time: ' . $util->format_time($data['duration']);
755 }
756
757 return $output;
758 }
759
760 public function delete_importer(\WP_REST_Request $request)
761 {
762 Logger::setRequestType('delete_importer');
763
764 $id = intval($request->get_param('id'));
765 $this->importer_manager->delete_importer($id);
766 return $this->http->end_rest_success(true);
767 }
768
769 public function attach_file(\WP_REST_Request $request)
770 {
771 $id = intval($request->get_param('id'));
772 $post_data = $this->sanitize($request->get_body_params());
773
774 $action = $post_data['action'];
775
776 $importer = $this->importer_manager->get_importer($id);
777
778 // TODO: Remove duplicate code, found in cron manager
779
780 switch ($action) {
781 case 'file_upload':
782 $attachment_id = $this->importer_manager->upload_file($importer, $_FILES['file']);
783 break;
784 case 'file_remote':
785 $raw_source = $post_data['remote_url'];
786 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer);
787 $source = apply_filters('iwp/importer/datasource/remote', $source, $raw_source, $importer);
788
789 $filetype = $importer->getParser();
790 if (is_null($filetype)) {
791 $filetype = $post_data['filetype'];
792 }
793
794 $attachment_id = $this->importer_manager->remote_file($importer, $source, $filetype, null, $importer->getId() . '-');
795 break;
796 case 'file_local':
797 $raw_source = $post_data['local_url'];
798 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer);
799 $source = apply_filters('iwp/importer/datasource/local', $source, $raw_source, $importer);
800 $attachment_id = $this->importer_manager->local_file($importer, $source);
801 break;
802 default:
803 $attachment_id = new \WP_Error('IWP_RM_1', 'Invalid form action');
804 break;
805 }
806
807 if (is_wp_error($attachment_id)) {
808 return $this->http->end_rest_error($attachment_id->get_error_message());
809 }
810
811 return $this->http->end_rest_success($importer->data());
812 }
813
814 public function get_file_process(\WP_REST_Request $request)
815 {
816 try {
817 $id = intval($request->get_param('id'));
818 $post_data = $this->sanitize($request->get_body_params());
819
820 $importer = $this->importer_manager->get_importer($id);
821 if (!$importer) {
822 return $this->http->end_rest_error('Invalid importer');
823 }
824
825 $this->importer_manager->clear_config_files($id, true);
826 $parser = $importer->getParser();
827
828 if ('xml' === $parser) {
829
830 $nodes = $this->importer_manager->process_xml_file($id, true);
831 $importer->setFileSetting('nodes', $nodes);
832 } elseif ('csv' === $parser) {
833
834 $delimiter = isset($post_data['delimiter']) ? $post_data['delimiter'] : null;
835 if (is_null($delimiter)) {
836 $delimiter = ',';
837 }
838
839 $enclosure = isset($post_data['enclosure']) ? $post_data['enclosure'] : null;
840 if (is_null($enclosure)) {
841 $enclosure = '"';
842 }
843
844 $count = $this->importer_manager->process_csv_file($id, $delimiter, $enclosure, true);
845
846 // Need fresh importer, due to process_csv_file importer modifications might get overwritten.
847 $importer = $this->importer_manager->get_importer($id);
848 $importer->setFileSetting('count', $count);
849 } else {
850
851 do_action('iwp/file-process/' . $parser, $importer, $post_data);
852 }
853
854 $importer->setFileSetting('processed', true);
855 $importer->save();
856
857 return $this->http->end_rest_success($importer->data());
858 } catch (\Exception $e) {
859 return $this->http->end_rest_error($e->getMessage());
860 }
861 }
862
863 public function get_file_preview(\WP_REST_Request $request)
864 {
865 try {
866 $id = intval($request->get_param('id'));
867 $post_data = $this->sanitize($request->get_body_params());
868 $importer = $this->importer_manager->get_importer($id);
869
870 $import_file_exists = $this->filesystem->file_exists($importer->getFile());
871 if (is_wp_error($import_file_exists)) {
872 throw new \Exception("Unable to load preview, " . $import_file_exists->get_error_message());
873 }
874
875 $record_index = isset($post_data['record']) ? $post_data['record'] : null;
876 if (is_null($record_index)) {
877 $record_index = 0;
878 }
879
880 // Temp set file_encoding
881 if (isset($post_data['file_encoding'])) {
882 $importer->setFileSetting('file_encoding', $post_data['file_encoding']);
883 }
884
885 if ($importer->getParser() === 'xml') {
886
887 $config = $this->importer_manager->get_config($importer, true);
888 $file = $this->importer_manager->get_xml_file($importer, $config);
889
890 $base_path = $post_data['base_path'];
891 if (!is_null($base_path)) {
892 $file->setRecordPath($base_path);
893 }
894
895 $preview = new XMLPreview($file, $base_path);
896 $result = $preview->data();
897 if (is_wp_error($result)) {
898 return $this->http->end_rest_error($result);
899 }
900
901 return $this->http->end_rest_success($result[0]);
902 } elseif ($importer->getParser() === 'csv') {
903
904 $config = $this->importer_manager->get_config($importer, true);
905 $file = $this->importer_manager->get_csv_file($importer, $config);
906
907 $clear_config = false;
908 if (!is_null($post_data['delimiter']) && $post_data['delimiter'] !== $file->getDelimiter()) {
909 $clear_config = true;
910 } elseif (!is_null($post_data['enclosure']) && $post_data['enclosure'] !== $file->getEnclosure()) {
911 $clear_config = true;
912 }
913
914 if ($clear_config) {
915 $this->importer_manager->clear_config_files($importer->getId(), true);
916 $config = $this->importer_manager->get_config($importer, true);
917 $file = $this->importer_manager->get_csv_file($importer, $config);
918 }
919
920 $delimiter = $post_data['delimiter'];
921 if (!is_null($delimiter)) {
922 $file->setDelimiter($delimiter);
923 }
924
925 $enclosure = $post_data['enclosure'];
926 if (!is_null($enclosure)) {
927 $file->setEnclosure($enclosure);
928 }
929
930 // parse bool param from string
931 $show_headings = $post_data['show_headings'];
932 if (in_array($show_headings, ['true', 'false'])) {
933 $show_headings = $show_headings === 'true' ? true : false;
934 }
935
936 if (is_null($show_headings)) {
937 $show_headings = $importer->getFileSetting('show_headings');
938 }
939
940 $preview = new CSVPreview($file);
941 $result = $preview->data($record_index, $show_headings);
942 if (is_wp_error($result)) {
943 return $this->http->end_rest_error($result);
944 }
945
946 return $this->http->end_rest_success($result);
947 } else {
948
949 $result = apply_filters('iwp/file-preview/' . $importer->getParser(), null, $importer);
950 if (is_wp_error($result)) {
951 return $this->http->end_rest_error($result);
952 }
953
954 return $this->http->end_rest_success($result);
955 }
956 } catch (\Exception $error) {
957 return $this->http->end_rest_error($error->getMessage());
958 }
959 }
960
961 public function get_preview(\WP_REST_Request $request)
962 {
963 // if no fields have been posted send all previews
964 try {
965 $id = intval($request->get_param('id'));
966 $importer = $this->importer_manager->get_importer($id);
967 $import_file_exists = $this->filesystem->file_exists($importer->getFile());
968 if (is_wp_error($import_file_exists)) {
969 throw new \Exception("Unable to load preview, " . $import_file_exists->get_error_message());
970 }
971
972 $parser = $importer->getParser();
973
974 $fields = $this->sanitize($request->get_body_params());
975 if (is_null($fields) || empty($fields)) {
976 $fields = $importer->getMap();
977 }
978
979 if ('xml' === $parser) {
980 $result = $this->importer_manager->preview_xml_file($importer, $fields);
981 } elseif ('csv' === $parser) {
982 $row = 0;
983 if ($importer->getFileSetting('show_headings') === true) {
984 $row = 1;
985 }
986 $result = $this->importer_manager->preview_csv_file($importer, $fields, $row);
987 } else {
988
989 $result = apply_filters('iwp/record-preview/' . $parser, [], $importer, $fields);
990 if (is_wp_error($result)) {
991 return $this->http->end_rest_error($result);
992 }
993
994 return $this->http->end_rest_success($result);
995 }
996
997 return $this->http->end_rest_success($result);
998 } catch (\Exception $error) {
999 return $this->http->end_rest_error($error->getMessage());
1000 }
1001 }
1002
1003 /**
1004 * Trigger a new import.
1005 *
1006 * @param \WP_REST_Request $request
1007 * @return array
1008 */
1009 public function init_import(\WP_REST_Request $request)
1010 {
1011 $id = intval($request->get_param('id'));
1012
1013 Logger::setRequestType('rest::init_import');
1014
1015 Logger::write('init_import -start', $id);
1016
1017 $importer_data = $this->importer_manager->get_importer($id);
1018
1019 // clear existing
1020 ImporterState::clear_options($importer_data->getId());
1021
1022 // This is used for storing version on imported records
1023 $session_id = md5($importer_data->getId() . time());
1024 update_post_meta($importer_data->getId(), '_iwp_session', $session_id);
1025
1026 Logger::clearRequestType();
1027
1028 return $this->http->end_rest_success([
1029 'session' => $session_id
1030 ]);
1031 }
1032
1033 public function run_import(\WP_REST_Request $request)
1034 {
1035 $this->http->set_stream_headers();
1036
1037 Logger::setRequestType('rest::run_import');
1038
1039 $session = $request->get_param('session');
1040 $user = uniqid('iwp', true);
1041 $id = intval($request->get_param('id'));
1042 Logger::write('run_import -session=' . $session, $id);
1043
1044 $importer_data = $this->importer_manager->get_importer($id);
1045 Logger::write('run_import -import=start', $id);
1046
1047 $state = $this->importer_manager->import($importer_data->getId(), $user, $session);
1048 $state['message'] = $this->generate_status_message($state);
1049
1050 Logger::clearRequestType();
1051
1052 return $this->http->end_rest_success($state);
1053 }
1054
1055 public function pause_import(\WP_REST_Request $request)
1056 {
1057 $id = intval($request->get_param('id'));
1058 $paused = $this->sanitize($request->get_param('paused'), 'paused');
1059
1060 $importer_data = $this->importer_manager->get_importer($id);
1061 $user = uniqid('iwp', true);
1062
1063 $state = ImporterState::wait_for_lock($importer_data->getId(), $user, function () use ($importer_data, $paused) {
1064 $state = ImporterState::get_state($importer_data->getId());
1065
1066
1067 if ($paused === 'no') {
1068 $state['status'] = 'running';
1069 } else {
1070 $state['status'] = 'paused';
1071 }
1072
1073 ImporterState::set_state($importer_data->getId(), $state);
1074 return $state;
1075 });
1076
1077 return $this->http->end_rest_success($state);
1078 }
1079
1080 public function stop_import(\WP_REST_Request $request)
1081 {
1082 $id = intval($request->get_param('id'));
1083
1084 $importer_data = $this->importer_manager->get_importer($id);
1085
1086 $user = uniqid('iwp');
1087
1088 $state = ImporterState::wait_for_lock($importer_data->getId(), $user, function () use ($importer_data) {
1089 $state = ImporterState::get_state($importer_data->getId());
1090 $state['status'] = 'cancelled';
1091 ImporterState::set_state($importer_data->getId(), $state);
1092 return $state;
1093 });
1094
1095 return $this->http->end_rest_success($state);
1096 }
1097
1098 /**
1099 * Get field options for current template
1100 *
1101 * @param \WP_REST_Request $request
1102 * @return void
1103 */
1104 public function get_template_field_options(\WP_REST_Request $request)
1105 {
1106 $id = intval($request->get_param('id'));
1107 $field = $this->sanitize($request->get_param('field'), 'field');
1108
1109 $importer_data = $this->importer_manager->get_importer($id);
1110 $template = $this->importer_manager->get_importer_template($id);
1111
1112 return $this->http->end_rest_success($template->get_field_options($field, $importer_data));
1113 }
1114
1115 public function get_logs(\WP_REST_Request $request)
1116 {
1117 $id = intval($request->get_param('id'));
1118 $importer_data = $this->importer_manager->get_importer($id);
1119 $logs = $this->importer_manager->get_importer_logs($importer_data);
1120 return $this->http->end_rest_success(array_reverse($logs));
1121 }
1122
1123 public function get_log(\WP_REST_Request $request)
1124 {
1125 $id = intval($request->get_param('id'));
1126 $session = $this->sanitize($request->get_param('session'), 'session');
1127 $page = intval($request->get_param('page'));
1128 if ($page < 1) {
1129 $page = 1;
1130 }
1131 $importer_data = $this->importer_manager->get_importer($id);
1132 $log = $this->importer_manager->get_importer_log($importer_data, $session, $page, 500);
1133 $status = $this->importer_manager->get_importer_status_report($importer_data, $session);
1134 return $this->http->end_rest_success(['logs' => $log, 'status' => $status]);
1135 }
1136
1137 public function get_debug_log(\WP_REST_Request $request)
1138 {
1139 $id = intval($request->get_param('id'));
1140 $page = intval($request->get_param('page'));
1141 if ($page < 1) {
1142 $page = 1;
1143 }
1144 $importer_data = $this->importer_manager->get_importer($id);
1145 $log = $this->importer_manager->get_importer_debug_log($importer_data, $page, 100);
1146
1147 $download = Logger::getLogFile($importer_data->getId(), true);
1148 return $this->http->end_rest_success(['log' => $log, 'download' => $download]);
1149 }
1150
1151 public function save_settings(\WP_REST_Request $request)
1152 {
1153 $post_data = $request->get_body_params();
1154 $post_data = $this->sanitize($post_data);
1155
1156 $defaults = $this->properties->_default_settings();
1157
1158 $output = [];
1159
1160 foreach ($defaults as $setting => $default) {
1161 if (isset($post_data[$setting])) {
1162 if ('bool' === $default['type']) {
1163 // Handle Boolean
1164 if (is_bool($post_data[$setting])) {
1165 $output[$setting] = $post_data[$setting];
1166 } elseif (in_array($post_data[$setting], ['true', 'false'])) {
1167 $output[$setting] = $post_data[$setting] === 'true' ? true : false;
1168 } else {
1169 $output[$setting] = boolval($post_data[$setting]);
1170 }
1171 } elseif ('number' === $default['type']) {
1172 $output[$setting] = intval($post_data[$setting]);
1173 } else {
1174 $output[$setting] = $post_data[$setting];
1175 }
1176 } else {
1177 $output[$setting] = $default['value'];
1178 }
1179 }
1180
1181 update_site_option('iwp_settings', $output);
1182
1183 return $this->http->end_rest_success($this->properties->get_settings());
1184 }
1185
1186 public function get_settings(\WP_REST_Request $request = null)
1187 {
1188 $output = $this->properties->get_settings();
1189 return $this->http->end_rest_success($output);
1190 }
1191
1192 public function get_template(\WP_REST_Request $request = null)
1193 {
1194 Logger::setRequestType('get_template');
1195
1196 $importer_id = $request->get_param('id');
1197 $importer_model = $this->importer_manager->get_importer($importer_id);
1198 $importer_template = $importer_model->getTemplate();
1199
1200 $templates = $this->importer_manager->get_templates();
1201
1202 if (!isset($templates[$importer_template])) {
1203 return $this->http->end_rest_error("Invalid template \"" . $importer_template . "\"");
1204 }
1205
1206 $template_id = $templates[$importer_template];
1207 $template_class = $this->template_manager->load_template($template_id);
1208
1209 $output = [
1210 'id' => $template_id,
1211 'label' => $template_class->get_name(),
1212 'map' => $template_class->get_fields($importer_model),
1213 'settings' => $template_class->register_settings(),
1214 'options' => $template_class->register_options(),
1215 ];
1216 return $this->http->end_rest_success($output);
1217 }
1218
1219 public function export_importers(\WP_REST_Request $request = null)
1220 {
1221 Logger::setRequestType('export_importers');
1222
1223 $importer_ids = $request->get_param('ids');
1224
1225 $sql_ids = array_map(function ($v) {
1226 return "'" . esc_sql($v) . "'";
1227 }, $importer_ids);
1228 $sql_ids = implode(',', $sql_ids);
1229
1230 $output = [];
1231
1232 /**
1233 * @var \WPDB $wpdb
1234 */
1235 global $wpdb;
1236 $results = $wpdb->get_results("SELECT post_title, post_content from {$wpdb->posts} WHERE post_type='" . IWP_POST_TYPE . "' AND ID IN (" . $sql_ids . ")", ARRAY_A);
1237 foreach ($results as $result) {
1238
1239 $data = unserialize($result['post_content']);
1240
1241 unset($data['file']['id']);
1242 unset($data['file']['settings']['count']);
1243 unset($data['file']['settings']['processed']);
1244
1245
1246 $row = [
1247 'name' => $result['post_title'],
1248 'data' => $data
1249 ];
1250
1251 if ($this->importer_manager->is_debug()) {
1252 $row['raw'] = base64_encode($result['post_content']);
1253 }
1254
1255 $output[] = $row;
1256 }
1257
1258 $json = json_encode($output);
1259
1260 header('Content-disposition: attachment; filename="ImportWP-export-' . date('Y-m-d') . '.json"');
1261 header('Content-type: "application/json"; charset="utf8"');
1262 header('Expires: 0');
1263 header('Cache-Control: must-revalidate');
1264 header('Pragma: public');
1265 header('Content-Length: ' . strlen($json));
1266
1267 echo $json;
1268 die();
1269 }
1270
1271 public function import_exporters(\WP_REST_Request $request = null)
1272 {
1273 Logger::setRequestType('import_exporters');
1274
1275 $upload = $this->filesystem->upload_file($_FILES['file']);
1276 if (is_wp_error($upload)) {
1277 return $this->http->end_rest_error($upload->get_error_message());
1278 }
1279
1280 $json_contents = file_get_contents($upload['dest']);
1281 @unlink($upload['dest']);
1282
1283 $contents = json_decode($json_contents, true);
1284 $counter = 0;
1285 $errors = [];
1286 if (!empty($contents)) {
1287 foreach ($contents as $importer) {
1288
1289 $result = wp_insert_post([
1290 'post_type' => IWP_POST_TYPE,
1291 'post_title' => $importer['name'],
1292 'post_status' => 'publish',
1293 'post_author' => get_current_user_id(),
1294 'post_content' => serialize($importer['data'])
1295 ], true);
1296
1297 if (is_wp_error($result)) {
1298 $errors[] = $result->get_error_message();
1299 continue;
1300 }
1301
1302 $counter++;
1303 }
1304 }
1305
1306 if (empty($counter)) {
1307 return $this->http->end_rest_error('No Importers found.');
1308 }
1309
1310 return $this->http->end_rest_success("Import Complete, {$counter} Importer" . ($counter > 1 ? 's' : '') . '.');
1311 }
1312
1313 public function save_exporter(\WP_REST_Request $request = null)
1314 {
1315 Logger::setRequestType('save_exporter');
1316
1317 $post_data = $request->get_body_params();
1318 $id = isset($post_data['id']) ? intval($post_data['id']) : null;
1319
1320
1321 $exporter = new ExporterModel($id, $this->importer_manager->is_debug());
1322
1323 if (isset($post_data['name'])) {
1324 $exporter->setName($post_data['name']);
1325 }
1326
1327 if (isset($post_data['type'])) {
1328 $exporter->setType($post_data['type']);
1329 }
1330
1331 if (isset($post_data['file_type'])) {
1332 $exporter->setFileType($post_data['file_type']);
1333 }
1334
1335 if (isset($post_data['fields']) || $id > 0) {
1336 $exporter->setFields(isset($post_data['fields']) ? $post_data['fields'] : []);
1337 }
1338
1339 if (isset($post_data['filters']) || $id > 0) {
1340 $exporter->setFilters(isset($post_data['filters']) ? $post_data['filters'] : []);
1341 }
1342
1343 if (isset($post_data['unique_identifier'])) {
1344 $exporter->setUniqueIdentifier($post_data['unique_identifier']);
1345 }
1346
1347 if (isset($post_data['export_method'])) {
1348 $exporter->setExportMethod($post_data['export_method']);
1349 }
1350
1351 if (isset($post_data['cron'])) {
1352
1353 // TODO: Save cron settings
1354
1355 $cron = $this->sanitize_setting($post_data['cron']);
1356 $exporter->setCron($cron);
1357 }
1358
1359 $result = $exporter->save();
1360 if (is_wp_error($result)) {
1361 return $this->http->end_rest_error($result->get_error_message());
1362 }
1363 return $this->http->end_rest_success($exporter->data());
1364 }
1365
1366 public function get_exporters(\WP_REST_Request $request = null)
1367 {
1368 Logger::setRequestType('get_exporters');
1369
1370 $exporters = $this->exporter_manager->get_exporters();
1371 $result = [];
1372
1373 foreach ($exporters as $exporter) {
1374 $result[] = $exporter->data();
1375 }
1376
1377 return $this->http->end_rest_success($result);
1378 }
1379
1380 public function get_exporter(\WP_REST_Request $request = null)
1381 {
1382 Logger::setRequestType('get_exporter');
1383
1384 $id = intval($request->get_param('id'));
1385 $exporter_data = $this->exporter_manager->get_exporter($id);
1386 $response = $exporter_data->data('public');
1387 return $this->http->end_rest_success($response);
1388 }
1389
1390 public function delete_exporter(\WP_REST_Request $request = null)
1391 {
1392 Logger::setRequestType('delete_exporter');
1393
1394 $id = intval($request->get_param('id'));
1395 $this->exporter_manager->delete_exporter($id);
1396 return $this->http->end_rest_success(true);
1397 }
1398
1399 /**
1400 * Trigger a new export.
1401 *
1402 * @param \WP_REST_Request $request
1403 * @return array
1404 */
1405 public function init_export(\WP_REST_Request $request)
1406 {
1407 $id = intval($request->get_param('id'));
1408
1409 Logger::setRequestType('rest::init_export');
1410
1411 Logger::write('init_import -start', $id);
1412
1413 $exporter_data = $this->exporter_manager->get_exporter($id);
1414
1415 // clear existing
1416 ExporterState::clear_options($exporter_data->getId());
1417
1418 // This is used for storing version on imported records
1419 $session_id = md5($exporter_data->getId() . time());
1420 update_post_meta($exporter_data->getId(), '_iwp_session', $session_id);
1421
1422 Logger::clearRequestType();
1423
1424 return $this->http->end_rest_success([
1425 'session' => $session_id
1426 ]);
1427 }
1428
1429 public function run_exporter(\WP_REST_Request $request)
1430 {
1431 Logger::setRequestType('run_exporter');
1432
1433 $this->http->set_stream_headers();
1434
1435 $id = intval($request->get_param('id'));
1436 $session = $request->get_param('session');
1437 $user = uniqid('iwp', true);
1438
1439 $exporter_data = $this->exporter_manager->get_exporter($id);
1440
1441 $status = $this->exporter_manager->export($exporter_data, $user, $session);
1442 echo json_encode($status);
1443 // Logger::write(__CLASS__ . '::run_import -import=end -status=' . $status->get_status(), $id);
1444
1445 // if (!empty($this->output_cache)) {
1446 // echo $this->output_cache;
1447 // $this->output_cache = '';
1448 // }
1449
1450 // $output = $status->output();
1451 // $output['message'] = $this->generate_exporter_status_message($status);
1452 // echo json_encode($output) . "\n";
1453 die();
1454 }
1455
1456 public function get_exporter_status(\WP_REST_Request $request)
1457 {
1458 Logger::setRequestType('get_exporter_status');
1459
1460 $exporter_ids = $request->get_param('ids');
1461 $result = array();
1462 $query_data = array(
1463 'post_type' => EWP_POST_TYPE,
1464 'posts_per_page' => -1,
1465 'fields' => 'ids'
1466 );
1467
1468 if (!empty($exporter_ids)) {
1469 $query_data['post__in'] = $exporter_ids;
1470 }
1471
1472 $query = new \WP_Query($query_data);
1473
1474 if (!empty($query->posts)) {
1475 foreach ($query->posts as $post_id) {
1476
1477 $exporter = $this->exporter_manager->get_exporter($post_id);
1478 $status = ExporterState::get_state($post_id);
1479 $status['exporter'] = $post_id;
1480 $status['version'] = 2;
1481
1482 $current = $status['progress']['export']['current_row'];
1483 $end = $status['progress']['export']['end'] - $status['progress']['export']['start'];
1484 $status['progress'] = $end > 0 ? ($current / $end) * 100 : 0;
1485
1486 $output = '';
1487
1488 switch ($status['status']) {
1489 case 'cancelled':
1490 $output .= 'Export cancelled';
1491 break;
1492 case 'complete':
1493 $output .= 'Export complete';
1494 break;
1495 case 'running':
1496 $output .= 'Exporting: ' . $current . '/' . $end;
1497 break;
1498 }
1499
1500 $status['message'] = $output;
1501
1502 $result[] = $this->event_handler->run('iwp/exporter/status/output', [$status, $exporter]);
1503 }
1504 }
1505
1506 echo json_encode($result) . "\n";
1507 die();
1508 }
1509 }
1510