PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.15.1
Import WP – CSV & XML Import Export for WordPress v2.15.1
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 / Importer / Template / Template.php

Template.php in Import WP – CSV & XML Import Export for WordPress 2.15.1, at class/Common/Importer/Template/Template.php

1,235 lines 45.2 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\Importer\Template;
4
5 use ImportWP\Common\Attachment\Attachment;
6 use ImportWP\Common\Filesystem\Filesystem;
7 use ImportWP\Common\Ftp\Ftp;
8 use ImportWP\Common\Importer\File\XMLFile;
9 use ImportWP\Common\Importer\Mapper\AbstractMapper;
10 use ImportWP\Common\Importer\ParsedData;
11 use ImportWP\Common\Model\ImporterModel;
12 use ImportWP\Common\Util\Logger;
13 use ImportWP\Container;
14 use ImportWP\EventHandler;
15
16 class Template extends AbstractTemplate
17 {
18 /**
19 * Template name
20 *
21 * @var string
22 */
23 protected $name;
24 /**
25 * Mapper name
26 *
27 * @var string
28 */
29 protected $mapper;
30 /**
31 * @var ImporterModel
32 */
33 protected $importer;
34
35 /**
36 * Registered data groups
37 *
38 * @var string[]
39 */
40 protected $groups;
41
42 /**
43 * List of field option callbacks
44 *
45 * @var array
46 */
47 protected $field_options = [];
48
49 protected $default_template_options = [];
50
51 /**
52 *
53 * List of optional fields that are enabled by default
54 * @var string[]
55 */
56 protected $default_enabled_fields = [];
57
58 /**
59 * @var \WP_Error[] $errors
60 */
61 protected $errors = [];
62
63 /**
64 * @var EventHandler $event_handler
65 */
66 private $event_handler;
67
68 /**
69 * @var boolean
70 */
71 private $featured_set = false;
72
73 public function __construct(EventHandler $event_handler)
74 {
75 $this->event_handler = $event_handler;
76 $this->event_handler->run('template.init', [$this]);
77
78 $this->groups = $this->event_handler->run('template.data_groups', [$this->groups, $this]);
79
80 // Register field options callbacks
81 $this->field_options = [
82 '*.row_base' => [$this, 'get_row_base']
83 ];
84 $this->field_options = $this->event_handler->run('template.field_option_callbacks', [$this->field_options, $this]);
85 }
86
87 /**
88 * Get xml record base
89 *
90 * @param ImporterModel $importer_model
91 * @return array
92 */
93 public function get_row_base($importer_model)
94 {
95 /**
96 * @var ImporterManager $importer_manager
97 */
98 $importer_manager = Container::getInstance()->get('importer_manager');
99 $tmp = false;
100 $results = [];
101
102 if ($importer_model->getParser() !== 'xml') {
103 return $results;
104 }
105
106 $base_path = $importer_model->getFileSetting('base_path');
107 $nodes = $importer_model->getFileSetting('nodes');
108
109 $config = $importer_manager->get_config($importer_model->getId(), $tmp);
110
111 $filePath = $importer_model->getFile();
112 $file = new XMLFile($filePath, $config);
113 $file->setRecordPath($base_path);
114 $nodes = $file->get_node_list();
115
116 // Nodes that appear as a parent of another path have selectable children.
117 $parents = [];
118 foreach ($nodes as $node) {
119 $parent = $node;
120 while (($pos = strrpos($parent, '/')) !== false && $pos > 0) {
121 $parent = substr($parent, 0, $pos);
122 $parents[$parent] = true;
123 }
124 }
125
126 foreach ($nodes as $node) {
127 if (strpos($node, $base_path) !== 0) {
128 continue;
129 }
130
131 // Skip leaf nodes (e.g. /categories/category) — they have no selectable child nodes.
132 if (!isset($parents[$node])) {
133 continue;
134 }
135
136 $sub_node = substr($node, strlen($base_path));
137
138 $results[] = [
139 'value' => $sub_node,
140 'label' => $sub_node
141 ];
142 }
143
144 return $results;
145 }
146
147 public function get_name()
148 {
149 return $this->name;
150 }
151
152 public function get_mapper()
153 {
154 return $this->mapper;
155 }
156
157 public function get_importer()
158 {
159 return $this->importer;
160 }
161
162 public function get_fields(ImporterModel $importer = null)
163 {
164 $fields = $this->register();
165 $fields = $this->event_handler->run('template.fields', [$fields, $this, $importer]);
166 return $fields;
167 }
168
169 public function register()
170 {
171 return [];
172 }
173
174 public function register_hooks(ImporterModel $importer)
175 {
176 $this->importer = $importer;
177
178 add_filter('iwp/importer/before_mapper', array($this, 'pre_process'));
179 add_filter('iwp/status/record_inserted', [$this, 'display_record_info'], 10, 3);
180 add_filter('iwp/status/record_updated', [$this, 'display_record_info'], 10, 3);
181 }
182
183 public function unregister_hooks()
184 {
185 remove_filter('iwp/importer/before_mapper', array($this, 'pre_process'));
186 remove_filter('iwp/status/record_inserted', [$this, 'display_record_info'], 10, 3);
187 remove_filter('iwp/status/record_updated', [$this, 'display_record_info'], 10, 3);
188 }
189
190 /**
191 * @param string $message
192 * @param int $id
193 * @param ParsedData $data
194 * @return $string
195 */
196 public function display_record_info($message, $id, $data)
197 {
198
199 $fields = $data->getData();
200 if (!empty($fields)) {
201 $message .= ' (' . implode(', ', array_keys($fields)) . ')';
202 }
203
204 if (!empty($this->errors)) {
205 $errors = [];
206 foreach ($this->errors as $error) {
207 $errors[] = $error->get_error_message();
208 }
209
210 $message .= ', Errors: (' . implode(', ', $errors) . ')';
211 }
212
213 $this->errors = [];
214
215 return $message;
216 }
217
218 public function register_group($label, $key, $fields, $args = [])
219 {
220 if (isset($args['row_base']) && true === $args['row_base']) {
221
222 $fields = array_merge(
223 [$this->register_field(__('Repeater Node', 'jc-importer'), 'row_base', [
224 'type' => 'text',
225 'options' => 'callback',
226 'tooltip' => __('Select the path to the parent node containing values for this record, The preview when selecting data for each record should show a single record. Please note changing this will require updating references in this record.', 'jc-importer')
227 ])],
228 $fields
229 );
230 }
231
232 $tmp = [
233 'id' => $key,
234 'heading' => $label,
235 'type' => isset($args['type']) ? $args['type'] : 'group',
236 'fields' => $fields,
237 ];
238
239 if (isset($args['link']) && !empty($args['link'])) {
240 $tmp['link'] = $args['link'];
241 }
242
243 if (isset($args['condition']) && !empty($args['condition'])) {
244 $tmp['condition'] = $args['condition'];
245 }
246
247 // Allow for setting fields to be registered for the group
248 // currently only supporting toggle fields.
249 if (isset($args['settings']) && !empty($args['settings'])) {
250 $tmp['settings'] = $args['settings'];
251 }
252
253 // Field ids used to build the collapsed repeater row summary in the UI.
254 if (isset($args['row_summary']) && !empty($args['row_summary'])) {
255 $tmp['row_summary'] = array_values((array) $args['row_summary']);
256 }
257
258 return $tmp;
259 }
260
261 public function register_core_field($label, $key, $args = [])
262 {
263 $args['core'] = true;
264 return $this->register_field($label, $key, $args);
265 }
266
267 public function register_field($label, $key, $args = [])
268 {
269 $data = [
270 'id' => $key,
271 'label' => $label,
272 'type' => isset($args['type']) ? $args['type'] : 'field',
273 'core' => isset($args['core']) ? $args['core'] : false,
274 'tooltip' => isset($args['tooltip']) ? $args['tooltip'] : false
275 ];
276
277 if (isset($args['options'])) {
278 $data['options'] = $args['options'];
279 }
280
281 if (isset($args['default'])) {
282 $data['default'] = $args['default'];
283 }
284
285 if (isset($args['condition'])) {
286 $data['condition'] = $args['condition'];
287 }
288
289 return $data;
290 }
291
292 public function _register_attachment_setting_fields($display_conditions = [], $extra_fields = [], $disabled_fields = [])
293 {
294
295 $fields = [];
296
297 if (!in_array('_featured', $disabled_fields)) {
298 $fields[] = $this->register_field(__('Is Featured?', 'jc-importer'), '_featured', [
299 'default' => 'no',
300 'options' => [
301 ['value' => 'no', 'label' => __('No', 'jc-importer')],
302 ['value' => 'yes', 'label' => __('Yes', 'jc-importer')],
303 ],
304 'tooltip' => __('Is the attachment the featured image for the current post.', 'jc-importer')
305 ]);
306 }
307
308 $fields = array_merge($fields, [
309 $this->register_field(__('Download', 'jc-importer'), '_download', [
310 'default' => 'remote',
311 'options' => [
312 ['value' => 'remote', 'label' => __('Remote URL', 'jc-importer')],
313 ['value' => 'ftp', 'label' => __('FTP', 'jc-importer')],
314 ['value' => 'local', 'label' => __('Local Filesystem', 'jc-importer')],
315 ['value' => 'media', 'label' => __('Media Library', 'jc-importer')],
316 ],
317 'tooltip' => __('Select how the attachment is being downloaded.', 'jc-importer')
318 ]),
319 $this->register_field(__('Host', 'jc-importer'), '_ftp_host', [
320 'condition' => ['_download', '==', 'ftp'],
321 'tooltip' => __('Enter the FTP hostname', 'jc-importer')
322 ]),
323 $this->register_field(__('Username', 'jc-importer'), '_ftp_user', [
324 'condition' => ['_download', '==', 'ftp'],
325 'tooltip' => __('Enter the FTP username', 'jc-importer')
326 ]),
327 $this->register_field(__('Password', 'jc-importer'), '_ftp_pass', [
328 'condition' => ['_download', '==', 'ftp'],
329 'tooltip' => __('Enter the FTP password', 'jc-importer')
330 ]),
331 $this->register_field(__('Path', 'jc-importer'), '_ftp_path', [
332 'condition' => ['_download', '==', 'ftp'],
333 'tooltip' => __('Enter the FTP base path, this is prefixed onto the Location field, leave empty to be ignore', 'jc-importer')
334 ]),
335 $this->register_field(__('Base URL', 'jc-importer'), '_remote_url', [
336 'condition' => ['_download', '==', 'remote'],
337 'tooltip' => __('Enter the base url, this is prefixed onto the Location field, leave empty to be ignore', 'jc-importer')
338 ]),
339 $this->register_field(__('Base URL', 'jc-importer'), '_local_url', [
340 'condition' => ['_download', '==', 'local'],
341 'tooltip' => __('Enter the base path from this servers root file system, this is prefixed onto the Location field, leave empty to be ignore', 'jc-importer')
342 ]),
343
344 $this->register_field(__('Permissions', 'jc-importer'), '_enable_image_hash', [
345 'condition' => ['_download', '!=', 'media'],
346 'default' => 'yes',
347 'options' => [
348 ['value' => 'no', 'label' => __('Always download new files', 'jc-importer')],
349 ['value' => 'yes', 'label' => __('Search media library before downloading new files', 'jc-importer')],
350 ],
351 'tooltip' => __('Enable to stop duplicate images by searching the media library before downloading new files.', 'jc-importer')
352 ]),
353 $this->register_field(__('Delimiter', 'jc-importer'), '_delimiter', [
354 'type' => 'text',
355 'tooltip' => sprintf(__('A single character used to seperate attachments when listing multiple, Leave empty to use the default: %s', 'jc-importer'), ',')
356 ]),
357
358 ]);
359
360 if (!in_array('_meta', $disabled_fields)) {
361 $fields[] = $this->register_group(__('Attachment Meta', 'jc-importer'), '_meta', [
362 $this->register_field(__('Enable Meta', 'jc-importer'), '_enabled', [
363 'default' => 'no',
364 'options' => [
365 ['value' => 'no', 'label' => __('No', 'jc-importer')],
366 ['value' => 'yes', 'label' => __('Yes', 'jc-importer')],
367 ],
368 'type' => 'select',
369 'tooltip' => __('Enable/Disable the fields to import attachment meta data.', 'jc-importer')
370 ]),
371 $this->register_field(__('Alt Text', 'jc-importer'), '_alt', [
372 'condition' => ['_enabled', '==', 'yes'],
373 'tooltip' => __('Image attachment alt text.', 'jc-importer'),
374 ]),
375 $this->register_field(__('Title Text', 'jc-importer'), '_title', [
376 'condition' => ['_enabled', '==', 'yes'],
377 'tooltip' => __('Attachments title text.', 'jc-importer')
378 ]),
379 $this->register_field(__('Caption Text', 'jc-importer'), '_caption', [
380 'condition' => ['_enabled', '==', 'yes'],
381 'tooltip' => __('Image attachments caption text.', 'jc-importer')
382 ]),
383 $this->register_field(__('Description Text', 'jc-importer'), '_description', [
384 'condition' => ['_enabled', '==', 'yes'],
385 'tooltip' => __('Attachments description text.', 'jc-importer')
386 ])
387 ]);
388 }
389
390 return $this->register_group(__('Settings', 'jc-importer'), 'settings', array_merge($extra_fields, $fields), ['type' => 'settings', 'condition' => $display_conditions]);
391 }
392
393 public function register_attachment_fields($label = 'Images & Attachments', $name = 'attachments', $field_label = 'Location', $group_args = null, $attachment_args = [])
394 {
395 if (is_null($group_args)) {
396 $group_args = ['type' => 'repeatable', 'row_base' => true, 'row_summary' => ['location'], 'link' => 'https://www.importwp.com/docs/how-to-import-wordpress-attachments-onto-a-post-type/'];
397 } else if (!isset($group_args['row_summary'])) {
398 $group_args['row_summary'] = ['location'];
399 }
400
401 $display_conditions = isset($attachment_args['conditions']) ? $attachment_args['conditions'] : [];
402 $extra_fields = isset($attachment_args['extra_fields']) ? $attachment_args['extra_fields'] : [];
403 $disabled_fields = isset($attachment_args['disabled_fields']) ? $attachment_args['disabled_fields'] : [];
404
405 return $this->register_group($label, $name, [
406 $this->register_field($field_label, 'location', [
407 'tooltip' => __('The source location of the file being attached.', 'jc-importer')
408 ]),
409 $this->_register_attachment_setting_fields($display_conditions, $extra_fields, $disabled_fields)
410 ], $group_args);
411 }
412
413 public function get_field_options($field_name, $id)
414 {
415 $callback = false;
416 foreach ($this->field_options as $callback_field_name => $temp_callback) {
417 if (strpos($callback_field_name, '*') !== false) {
418
419 $callback_field_name = str_replace('.', '\.', $callback_field_name);
420
421 $pattern = str_replace('*', '[\S]+', $callback_field_name);
422 if (1 !== preg_match("/^{$pattern}/i", $field_name)) {
423 continue;
424 }
425
426 $callback = $temp_callback;
427 break;
428 }
429
430 if ($field_name !== $callback_field_name) {
431 continue;
432 }
433
434 $callback = $temp_callback;
435 break;
436 }
437
438 if (!$callback) {
439 return false;
440 }
441
442 if (!method_exists($callback[0], $callback[1])) {
443 return false;
444 }
445
446 if (!is_callable($callback)) {
447 return false;
448 }
449
450 return call_user_func_array($callback, [$id]);
451 }
452
453 public function get_default_template_options()
454 {
455 return $this->default_template_options;
456 }
457
458 /**
459 * Alter fields before they are parsed
460 *
461 * @param array $fields
462 * @return array
463 */
464 public function field_map($fields)
465 {
466 return $fields;
467 }
468
469 public function config_field_map($field_map)
470 {
471 $template_fields = $this->field_map($field_map);
472
473 $field_groups = [
474 'default' => [
475 'id' => 'default',
476 'fields' => []
477 ]
478 ];
479
480 foreach ($template_fields as $key => $value) {
481
482 if (empty($value) || preg_match('/\.row_base$/', $key) !== 1) {
483 continue;
484 }
485
486 $group_id = substr($key, 0, strlen($key) - strlen('.row_base'));
487
488 $field_groups[$group_id] = [
489 'id' => $group_id,
490 'base' => $value,
491 'fields' => []
492 ];
493 }
494
495 foreach ($template_fields as $field_id => $field_value) {
496
497 $found = false;
498
499 foreach ($field_groups as $group_prefix => $group_settings) {
500 if (false === strpos($field_id, $group_prefix) || preg_match('/\.row_base$/', $field_id) === 1) {
501 continue;
502 }
503
504 $field_groups[$group_prefix]['fields'][$field_id] = $field_value;
505 $found = true;
506 }
507
508 if (false === $found) {
509 $field_groups['default']['fields'][$field_id] = $field_value;
510 }
511 }
512
513 if ($this->importer->has_custom_unique_identifier()) {
514
515 $ref = $this->importer->getSetting('unique_identifier_ref');
516
517 $field_groups['iwp'] = [
518 'id' => 'iwp',
519 'fields' => [
520 $this->importer->get_iwp_reference_meta_key() => (!is_null($ref) ? $ref : '')
521 ]
522 ];
523 }
524
525 return $field_groups;
526 }
527
528 /**
529 * Process data before record is importer.
530 *
531 * Alter data that is passed to the mapper.
532 *
533 * @param ParsedData $data
534 * @return ParsedData
535 */
536 public function pre_process(ParsedData $data)
537 {
538 $data = $this->pre_process_groups($data);
539 $this->event_handler->run('template.pre_process', [$data, $this->importer, $this]);
540 return $data;
541 }
542
543 public function process($post_id, ParsedData $data, ImporterModel $importer_model)
544 {
545 $this->featured_set = false;
546 $this->event_handler->run('template.process', [$post_id, $data, $importer_model, $this]);
547 }
548
549 /**
550 * Process data after record is importer.
551 *
552 * Use data that is returned from the mapper.
553 *
554 * @param int $post_id
555 * @param ParsedData $data
556 * @return void
557 */
558 public function post_process($post_id, ParsedData $data)
559 {
560 $this->event_handler->run('template.post_process', [$post_id, $data, $this]);
561 }
562
563 public function pre_process_groups(ParsedData $data)
564 {
565 // Allows virtual groups to be registered
566 $this->groups = $this->event_handler->run('template.pre_process_groups', [$this->groups, $data, $this]);
567
568 if (is_array($this->groups) && !empty($this->groups)) {
569 $map = $data->getData('default');
570 foreach ($this->groups as $group) {
571 $group_map = [];
572
573 foreach ($map as $field_key => $fields_map) {
574 if (preg_match('/^' . $group . '\.(.*?)$/', $field_key) === 1) {
575 $group_map[$field_key] = $fields_map;
576 }
577 }
578
579 $data->replace($group_map, $group);
580 }
581 }
582
583 return $data;
584 }
585
586 /**
587 * Process attachment fields
588 *
589 * @param int $post_id
590 * @param array $row
591 * @param string $row_prefix
592 * @param Filesystem $filesystem
593 * @param Ftp $ftp
594 * @param Attachment $attachment
595 */
596 public function process_attachment($post_id, $row, $row_prefix, $filesystem, $ftp, $attachment)
597 {
598 $delimiter = apply_filters('iwp/value_delimiter', ',');
599 $delimiter = apply_filters('iwp/attachment/value_delimiter', $delimiter);
600
601 if (isset($row[$row_prefix . 'settings._delimiter'])) {
602
603 if (strlen(trim($row[$row_prefix . 'settings._delimiter'])) === 1) {
604 $delimiter = trim($row[$row_prefix . 'settings._delimiter']);
605 }
606 } elseif (isset($row[$row_prefix . '_delimiter'])) {
607
608 if (strlen(trim($row[$row_prefix . '_delimiter'])) === 1) {
609 $delimiter = trim($row[$row_prefix . '_delimiter']);
610 }
611 }
612
613 $meta_delimiter = apply_filters('iwp/attachment/meta_delimiter', $delimiter);
614
615 $locations = isset($row[$row_prefix . 'location']) ? $row[$row_prefix . 'location'] : null;
616 $location_parts = explode($delimiter, $locations);
617 $location_parts = array_filter(array_map('trim', $location_parts));
618
619 if (isset($row[$row_prefix . 'settings._meta._title'])) {
620 $attachment_titles = explode($meta_delimiter, $row[$row_prefix . 'settings._meta._title']);
621 } elseif ($row[$row_prefix . '_meta._title']) {
622 $attachment_titles = explode($meta_delimiter, $row[$row_prefix . '_meta._title']);
623 } else {
624 $attachment_titles = null;
625 }
626
627 if (isset($row[$row_prefix . 'settings._meta._alt'])) {
628 $attachment_alts = explode($meta_delimiter, $row[$row_prefix . 'settings._meta._alt']);
629 } elseif (isset($row[$row_prefix . '_meta._alt'])) {
630 $attachment_alts = explode($meta_delimiter, $row[$row_prefix . '_meta._alt']);
631 } else {
632 $attachment_alts = null;
633 }
634
635 if (isset($row[$row_prefix . 'settings._meta._caption'])) {
636 $attachment_captions = explode($meta_delimiter, $row[$row_prefix . 'settings._meta._caption']);
637 } elseif (isset($row[$row_prefix . '_meta._caption'])) {
638 $attachment_captions = explode($meta_delimiter, $row[$row_prefix . '_meta._caption']);
639 } else {
640 $attachment_captions = null;
641 }
642
643 if (isset($row[$row_prefix . 'settings._meta._description'])) {
644 $attachment_descriptions = explode($meta_delimiter, $row[$row_prefix . 'settings._meta._description']);
645 } elseif (isset($row[$row_prefix . '_meta._description'])) {
646 $attachment_descriptions = explode($meta_delimiter, $row[$row_prefix . '_meta._description']);
647 } else {
648 $attachment_descriptions = null;
649 }
650
651 if (isset($row[$row_prefix . 'settings._enable_image_hash'])) {
652 $attachment_enable_image_hash = $row[$row_prefix . 'settings._enable_image_hash'];
653 } elseif (isset($row[$row_prefix . '_enable_image_hash'])) {
654 $attachment_enable_image_hash = $row[$row_prefix . '_enable_image_hash'];
655 } else {
656 $attachment_enable_image_hash = 'yes';
657 }
658
659 $attachment_ids = [];
660 $location_counter = 0;
661 foreach ($location_parts as $location) {
662
663 if (empty($location)) {
664 continue;
665 }
666
667 if (isset($row[$row_prefix . 'settings._download'])) {
668 $download = $row[$row_prefix . 'settings._download'];
669 } elseif (isset($row[$row_prefix . '_download'])) {
670 $download = $row[$row_prefix . '_download'];
671 } else {
672 $download = null;
673 }
674
675 if (isset($row[$row_prefix . 'settings._featured'])) {
676 $featured = $row[$row_prefix . 'settings._featured'];
677 } elseif (isset($row[$row_prefix . '_featured'])) {
678 $featured = $row[$row_prefix . '_featured'];
679 } else {
680 $featured = null;
681 }
682
683
684 $source = null;
685 $result = false;
686 $attachment_id = null;
687 $attachment_salt = '';
688
689 $location = trim($location);
690
691 switch ($download) {
692 case 'remote':
693
694 if (isset($row[$row_prefix . 'settings._remote_url'])) {
695 $base_url = $row[$row_prefix . 'settings._remote_url'];
696 } elseif (isset($row[$row_prefix . '_remote_url'])) {
697 $base_url = $row[$row_prefix . '_remote_url'];
698 } else {
699 $base_url = null;
700 }
701
702 // check if file hash is already stored
703 $source = $base_url . $location;
704 if (empty($source)) {
705 continue 2;
706 }
707
708
709 $attachment_salt = file_exists($source) ? md5_file($source) : '';
710 $attachment_id = 0;
711 if ($attachment_enable_image_hash == 'yes') {
712 $attachment_id = $attachment->get_attachment_by_hash($source);
713 }
714
715 // check to see if remote url matches file existing in media library
716 if ($attachment_id <= 0) {
717 $dir = wp_get_upload_dir();
718 if (str_starts_with($source, $dir['baseurl'] . '/')) {
719 $attachment_id = attachment_url_to_postid($source);
720 }
721 }
722
723 if ($attachment_id <= 0) {
724
725 $main_zip_file = false;
726 if ($base_url === 'iwp_zip') {
727 $main_zip = get_post_meta($this->importer->getId(), '_iwp_zip', true);
728 if ($main_zip && file_exists($main_zip)) {
729 $base_url .= '://' . $main_zip;
730 $main_zip_file = $main_zip;
731 }
732 }
733
734 $zip = $this->get_zip_source($base_url, $filesystem);
735 if ($zip !== false) {
736
737 if (!$main_zip_file && isset($zip['src'])) {
738
739 /**
740 * @var \ImportWP\Common\Http\Http $http
741 */
742 $http = Container::getInstance()->get('http');
743 $result = $http->download_file($zip['src'], $zip['name']);
744 if (is_wp_error($result)) {
745 break;
746 }
747
748 if (!$result) {
749 $result = new \WP_Error('IWP_HTTP_2', __('Error downloading zip file', 'jc-importer'));
750 break;
751 }
752 }
753
754 $result = $this->get_file_from_zip($main_zip_file ? $main_zip_file : $zip['name'], $location, $filesystem);
755 if (!$result) {
756 continue 2;
757 }
758
759 break;
760 }
761 }
762
763 if (apply_filters('iwp/template/process_attachment/enable_file_size_hash', false) === true) {
764
765 // check to see if the remote url image is the same size as the one on disk.
766 if ($attachment_id > 0 && $attachment_enable_image_hash == 'yes') {
767
768 $existing_file = get_attached_file($attachment_id, true);
769
770 // Remove -scaled from the file name if it exists
771 if ($existing_file && file_exists($existing_file)) {
772 $existing_file = str_replace('-scaled.', '.', $existing_file);
773 }
774
775 if ($existing_file && file_exists($existing_file)) {
776 $head = wp_remote_head($source);
777 if (!is_wp_error($head)) {
778
779 // get file size from the header
780 $header_key = apply_filters('iwp/template/process_attachment/remote_file_size_header_key', 'content-length');
781 $size = wp_remote_retrieve_header($head, $header_key);
782 $existing_file_size = filesize($existing_file);
783
784 if ($size != $existing_file_size) {
785
786 // append the size to the attachment salt
787 $attachment_salt .= $size;
788 $attachment_id = $attachment->get_attachment_by_hash($source, $attachment_salt);
789 }
790 }
791 }
792 }
793 }
794
795 $custom_filename = apply_filters('iwp/attachment/filename', null, $source);
796 if ($attachment_id <= 0) {
797 Logger::write(__CLASS__ . '::process__attachments -remote=' . $source . ' -filename=' . $custom_filename);
798 $result = $filesystem->download_file($source, null, null, $custom_filename);
799 }
800 break;
801 case 'ftp':
802
803 if (isset($row[$row_prefix . 'settings._ftp_user'])) {
804 $ftp_user = $row[$row_prefix . 'settings._ftp_user'];
805 } elseif (isset($row[$row_prefix . '_ftp_user'])) {
806 $ftp_user = $row[$row_prefix . '_ftp_user'];
807 } else {
808 $ftp_user = null;
809 }
810
811 if (isset($row[$row_prefix . 'settings._ftp_host'])) {
812 $ftp_host = $row[$row_prefix . 'settings._ftp_host'];
813 } elseif (isset($row[$row_prefix . '_ftp_host'])) {
814 $ftp_host = $row[$row_prefix . '_ftp_host'];
815 } else {
816 $ftp_host = null;
817 }
818
819 if (isset($row[$row_prefix . 'settings._ftp_pass'])) {
820 $ftp_pass = $row[$row_prefix . 'settings._ftp_pass'];
821 } elseif (isset($row[$row_prefix . '_ftp_pass'])) {
822 $ftp_pass = $row[$row_prefix . '_ftp_pass'];
823 } else {
824 $ftp_pass = null;
825 }
826
827 if (isset($row[$row_prefix . 'settings._ftp_path'])) {
828 $base_url = $row[$row_prefix . 'settings._ftp_path'];
829 } elseif (isset($row[$row_prefix . '_ftp_path'])) {
830 $base_url = $row[$row_prefix . '_ftp_path'];
831 } else {
832 $base_url = null;
833 }
834
835 // check if file hash is already stored
836 $source = $base_url . $location;
837 if (empty($source)) {
838 continue 2;
839 }
840
841 $attachment_salt = file_exists($source) ? md5_file($source) : '';
842 $attachment_id = 0;
843 if ($attachment_enable_image_hash == 'yes') {
844 $attachment_id = $attachment->get_attachment_by_hash($source, $attachment_salt);
845 }
846
847 if ($attachment_id <= 0) {
848
849 $main_zip_file = false;
850 if ($base_url === 'iwp_zip') {
851 $main_zip = get_post_meta($this->importer->getId(), '_iwp_zip', true);
852 if ($main_zip && file_exists($main_zip)) {
853 $base_url .= '://' . $main_zip;
854 $main_zip_file = $main_zip;
855 }
856 }
857
858 $zip = $this->get_zip_source($base_url, $filesystem);
859 if ($zip !== false) {
860
861 if (!$main_zip_file && isset($zip['src'])) {
862 $result = $ftp->download_file($zip['src'], $ftp_host, $ftp_user, $ftp_pass, $zip['name']);
863 if (is_wp_error($result)) {
864 break;
865 }
866 }
867
868 $result = $this->get_file_from_zip($main_zip_file ? $main_zip_file : $zip['name'], $location, $filesystem);
869 if (!$result) {
870 continue 2;
871 }
872
873 break;
874 }
875 }
876
877 $custom_filename = apply_filters('iwp/attachment/filename', null, $source);
878 if ($attachment_id <= 0) {
879 Logger::write(__CLASS__ . '::process__attachments -ftp=' . $source . ' -filename=' . $custom_filename);
880 $result = $ftp->download_file($source, $ftp_host, $ftp_user, $ftp_pass, $custom_filename);
881 }
882 break;
883 case 'local':
884
885 if (isset($row[$row_prefix . 'settings._local_url'])) {
886 $base_url = $row[$row_prefix . 'settings._local_url'];
887 } elseif (isset($row[$row_prefix . '_local_url'])) {
888 $base_url = $row[$row_prefix . '_local_url'];
889 } else {
890 $base_url = null;
891 }
892
893 // check if file hash is already stored
894 $source = $base_url . $location;
895 if (empty($source)) {
896 continue 2;
897 }
898
899 $attachment_salt = file_exists($source) ? md5_file($source) : '';
900 $attachment_id = 0;
901 if ($attachment_enable_image_hash == 'yes') {
902 $attachment_id = $attachment->get_attachment_by_hash($source, $attachment_salt);
903 }
904
905 if ($attachment_id <= 0) {
906
907 $main_zip_file = false;
908 if ($base_url === 'iwp_zip') {
909 $main_zip = get_post_meta($this->importer->getId(), '_iwp_zip', true);
910 if ($main_zip && file_exists($main_zip)) {
911 $base_url .= '://' . $main_zip;
912 $main_zip_file = $main_zip;
913 }
914 }
915
916 $zip = $this->get_zip_source($base_url, $filesystem);
917 if ($zip !== false) {
918
919 if (!$main_zip_file && isset($zip['src'])) {
920 $result = $filesystem->copy($zip['src'], $zip['name']);
921 if (is_wp_error($result)) {
922 break;
923 }
924 }
925
926 $result = $this->get_file_from_zip($main_zip_file ? $main_zip_file : $zip['name'], $location, $filesystem);
927 if (!$result) {
928 continue 2;
929 }
930
931 break;
932 }
933 }
934
935 $custom_filename = apply_filters('iwp/attachment/filename', null, $source);
936 if ($attachment_id <= 0) {
937 Logger::write(__CLASS__ . '::process__attachments -local=' . $source . ' -filename=' . $custom_filename);
938 $result = $filesystem->copy_file($source, null, $custom_filename);
939 }
940 break;
941 case 'media':
942 $source = $location;
943 if (empty($source)) {
944 continue 2;
945 }
946
947 $attachment_id = $attachment->attachment_partial_url_to_postid($source);
948 Logger::write(__CLASS__ . '::process__attachments -media=' . $source);
949
950 break;
951 }
952
953 if (isset($row[$row_prefix . 'settings._meta._enabled'])) {
954 $meta_enabled = $row[$row_prefix . 'settings._meta._enabled'] === 'yes' ? true : false;
955 } elseif (isset($row[$row_prefix . '_meta._enabled'])) {
956 $meta_enabled = $row[$row_prefix . '_meta._enabled'] === 'yes' ? true : false;
957 } else {
958 $meta_enabled = false;
959 }
960
961 // insert attachment
962 if ($attachment_id <= 0) {
963
964 if (is_wp_error($result)) {
965 Logger::write(__CLASS__ . '::process__attachments -error=' . $result->get_error_message());
966 $this->errors[] = $result;
967 continue;
968 }
969
970 if (!$result) {
971 continue;
972 }
973
974 $attachment_args = [];
975 if ($meta_enabled) {
976 $attachment_args['title'] = isset($attachment_titles[$location_counter]) ? $attachment_titles[$location_counter] : null;
977 $attachment_args['alt'] = isset($attachment_alts[$location_counter]) ? $attachment_alts[$location_counter] : null;
978 $attachment_args['caption'] = isset($attachment_captions[$location_counter]) ? $attachment_captions[$location_counter] : null;
979 $attachment_args['description'] = isset($attachment_descriptions[$location_counter]) ? $attachment_descriptions[$location_counter] : null;;
980 }
981
982 // resize attachment
983 if ($crop_details = apply_filters('iwp/importer/template/process_attachment/resize', '__return_false')) {
984
985 if (is_array($crop_details) && count($crop_details) == 3 && file_exists($result['dest'])) {
986
987 list($max_w, $max_h, $crop) = $crop_details;
988
989 if (!is_null($max_w)) {
990 $max_w = absint($max_w);
991 }
992 if (!is_null($max_h)) {
993 $max_h = absint($max_h);
994 }
995
996 $editor = wp_get_image_editor($result['dest']);
997 if (!is_wp_error($editor)) {
998 $editor->resize($max_w, $max_h, (bool)$crop);
999 $editor->save($result['dest']);
1000 } else {
1001 Logger::write(__CLASS__ . '::process__attachments -resize -error=' . $editor->get_error_message());
1002 }
1003 }
1004 }
1005
1006 $attachment_id = $attachment->insert_attachment($post_id, $result['dest'], $result['mime'], $attachment_args);
1007 if (is_wp_error($attachment_id)) {
1008 Logger::write(__CLASS__ . '::process__attachments -error=' . $attachment_id->get_error_message());
1009 continue;
1010 }
1011
1012 $attachment->generate_image_sizes($attachment_id, $result['dest']);
1013 $attachment->store_attachment_hash($attachment_id, $source, $attachment_salt);
1014 } else {
1015 // Update existing attachment meta
1016 if ($meta_enabled) {
1017 $post_data = [];
1018
1019 if (isset($attachment_titles[$location_counter])) {
1020 $post_data['post_title'] = $attachment_titles[$location_counter];
1021 }
1022
1023 if (isset($attachment_descriptions[$location_counter])) {
1024 $post_data['post_content'] = $attachment_descriptions[$location_counter];
1025 }
1026
1027 if (isset($attachment_captions[$location_counter])) {
1028 $post_data['post_excerpt'] = $attachment_captions[$location_counter];
1029 }
1030
1031 if (!empty($post_data)) {
1032 $post_data['ID'] = $attachment_id;
1033 wp_update_post($post_data);
1034 }
1035
1036 if (isset($attachment_alts[$location_counter])) {
1037 update_post_meta($attachment_id, '_wp_attachment_image_alt', $attachment_alts[$location_counter]);
1038 }
1039 }
1040 }
1041
1042 $attachment_ids[] = $attachment_id;
1043 $attachment_url = wp_get_attachment_url($attachment_id);
1044 $this->_attachments[] = $attachment_url;
1045
1046 Logger::write(__CLASS__ . '::process__attachments -id=' . $attachment_id . ' -url=' . $attachment_url);
1047
1048 // set featured
1049 if ('yes' === $featured && false === $this->featured_set) {
1050 update_post_meta($post_id, '_thumbnail_id', $attachment_id);
1051 $this->featured_set = true;
1052 }
1053
1054 $location_counter++;
1055 }
1056
1057 return $attachment_ids;
1058 }
1059
1060 /**
1061 * Remove custom field meta fields from the provided array based on importer permissions.
1062 *
1063 * @param string[string] $custom_fields
1064 * @param ParsedData $data
1065 * @param string $group_name
1066 * @param string $permission_key
1067 * @param string $prefix
1068 * @return string[string]
1069 */
1070 public function process_attachment_meta_permissions($custom_fields, $data, $group_name, $permission_key, $prefix)
1071 {
1072 $allowed = $data->permission()->validate([
1073 $permission_key . '._alt' => '',
1074 $permission_key . '._title' => '',
1075 $permission_key . '._caption' => '',
1076 $permission_key . '._description' => ''
1077 ], $data->getMethod(), $group_name);
1078
1079 if (!isset($allowed[$permission_key . '._alt'])) {
1080 // remove alt
1081 unset($custom_fields[$prefix . 'settings._meta._alt']);
1082 }
1083 if (!isset($allowed[$permission_key . '._title'])) {
1084 // remove title
1085 unset($custom_fields[$prefix . 'settings._meta._title']);
1086 }
1087 if (!isset($allowed[$permission_key . '._caption'])) {
1088 // remove caption
1089 unset($custom_fields[$prefix . 'settings._meta._caption']);
1090 }
1091 if (!isset($allowed[$permission_key . '._description'])) {
1092 // remove description
1093 unset($custom_fields[$prefix . 'settings._meta._description']);
1094 }
1095
1096 return $custom_fields;
1097 }
1098
1099 /**
1100 * Add error message
1101 *
1102 * @param string|\WP_Error $error
1103 * @return void
1104 */
1105 public function add_error($error)
1106 {
1107 if (!is_wp_error($error)) {
1108 $error = new \WP_Error('IWP_TEMP_ERR', $error);
1109 }
1110
1111 $this->errors[] = $error;
1112 }
1113
1114 /**
1115 * Convert fields/headings to data map
1116 *
1117 * @param mixed $fields
1118 * @param ImporterModel $importer
1119 * @return array
1120 */
1121 public function generate_field_map($fields, $importer)
1122 {
1123 return ['enabled' => [], 'map' => []];
1124 }
1125
1126 public function get_zip_source($base_url, $filesystem)
1127 {
1128 $zip_parts = [];
1129 if (preg_match('/^iwp_zip:\/\/(.*?)$/', $base_url, $zip_parts) === 1) {
1130
1131 $iwp_tmp = $filesystem->get_temp_directory();
1132
1133 $iwp_tmp .= DIRECTORY_SEPARATOR . 'zip';
1134 if (!is_dir($iwp_tmp)) {
1135 mkdir($iwp_tmp);
1136 }
1137
1138 $hash = md5($base_url);
1139 $iwp_tmp .= DIRECTORY_SEPARATOR . $hash . '.zip';
1140 if (!file_exists($iwp_tmp)) {
1141 return ['src' => $zip_parts[1], 'name' => $iwp_tmp];
1142 }
1143
1144 return ['name' => $iwp_tmp];
1145 }
1146
1147 return false;
1148 }
1149
1150 public function get_file_from_zip($zip_path, $filename, $filesystem)
1151 {
1152 $zip = new \ZipArchive();
1153 if ($zip->open($zip_path) === true) {
1154 $output_data = $zip->getFromName($filename);
1155 if ($output_data === false) {
1156 return false;
1157 }
1158
1159 return $filesystem->string_to_file($output_data, $filename);
1160 }
1161
1162 return false;
1163 }
1164
1165 public function try_use_main_zip($base_url, $location)
1166 {
1167 if ($base_url === 'iwp_zip') {
1168
1169 $main_zip = get_post_meta($this->importer->getId(), '_iwp_zip', true);
1170 $source = $main_zip . $location;
1171 $base_url .= $main_zip;
1172 }
1173 }
1174
1175 public function get_permission_fields($importer_model)
1176 {
1177 return [];
1178 }
1179
1180 public function register_settings() {}
1181
1182 public function register_options()
1183 {
1184 return [];
1185 }
1186
1187 public function get_default_enabled_fields()
1188 {
1189 return $this->default_enabled_fields;
1190 }
1191
1192
1193 public function get_unique_identifier_options($importer_model, $unique_fields = [])
1194 {
1195 $output = [];
1196 return $output;
1197 }
1198
1199 public function get_unique_identifier_options_from_map($importer_model, $unique_fields, $field_map, $optional_fields)
1200 {
1201 $output = [];
1202 $mapped_data = $importer_model->getMap();
1203
1204 foreach ($field_map as $field_id => $field_map_key) {
1205
1206 if (isset($output[$field_id])) {
1207 continue;
1208 }
1209
1210 $output[$field_id] = [
1211 'value' => $field_id,
1212 'label' => $field_id,
1213 'uid' => false,
1214 'active' => false,
1215 ];
1216
1217 if (in_array($field_id, $unique_fields)) {
1218 $output[$field_id]['uid'] = true;
1219 }
1220
1221 if (!isset($mapped_data[$field_map_key]) || empty($mapped_data[$field_map_key])) {
1222 continue;
1223 }
1224
1225 if (in_array($field_id, $optional_fields) && true !== $importer_model->isEnabledField($field_map_key)) {
1226 continue;
1227 }
1228
1229 $output[$field_id]['active'] = true;
1230 }
1231
1232 return $output;
1233 }
1234 }
1235